diff --git a/docs/work-items/ET-007/00-business-request.md b/docs/work-items/ET-007/00-business-request.md
new file mode 100644
index 0000000..545e408
--- /dev/null
+++ b/docs/work-items/ET-007/00-business-request.md
@@ -0,0 +1,7 @@
+# Business Request: ET-005: Спутниковая карта (Схема/Спутник)
+
+Work Item ID: ET-007
+
+## Description
+
+TBD
diff --git a/docs/work-items/ET-008/00-business-request.md b/docs/work-items/ET-008/00-business-request.md
new file mode 100644
index 0000000..753c205
--- /dev/null
+++ b/docs/work-items/ET-008/00-business-request.md
@@ -0,0 +1,80 @@
+---
+type: business-request
+work_item_id: ET-008
+title: "Smoke test analyst integration"
+created_at: 2026-05-31
+source: pipeline-smoke
+requester: claude-bot
+synthetic: true
+---
+
+# Бизнес-запрос — ET-008 (Smoke test analyst integration)
+
+## Контекст
+
+Это **smoke-работа** для проверки интеграции аналитика в пайплайн
+`analyst → architect → coder → tester`. Реального заказчика нет;
+запрос синтезирован, чтобы проверить, что:
+
+1. Аналитик умеет создать полный пакет артефактов
+ (BRD / TRZ / AC / test-plan / UI test cases) без ручного вмешательства.
+2. Архитектор может декомпозировать ТЗ в исполнимый план.
+3. Кодер может реализовать минимальное изменение по плану.
+4. Тестировщик может прогнать функциональные и Playwright-тесты,
+ и автоматически закрыть задачу.
+
+В отличие от ET-007 (dry-run по реальной фиче), ET-008 — это **smoke**:
+скоуп ещё уже, никакого нового UX-функционала для пользователя нет,
+только технический маркер, видимый Playwright-у.
+
+Требования к синтетическому скоупу (жёстче, чем у ET-007):
+
+- Изменение исключительно во фронтенде (`src/web/index.html`,
+ `src/web/app.css`). JavaScript **не трогаем**.
+- Не ломает существующий функционал: карта, темы, роутинг, GPX, рельеф
+ (hillshade/TRI), POI, разведка, линейка, единицы измерения, поиск,
+ переключатели слоёв.
+- Виден Playwright-у при специальном условии (`?smoke=et-008` в URL),
+ но **невидим** обычному пользователю при чистой загрузке.
+- Тривиально откатывается: одна `
` в `index.html` + один CSS-блок.
+- Не зависит от сети, БД, времени, пользовательских действий.
+
+## Исходная формулировка
+
+> Нужен невидимый по умолчанию DOM-маркер, который сигнализирует, что
+> текущая сборка прошла полный конвейер аналитик → архитектор → кодер →
+> тестировщик. Маркер должен появляться в углу карты только когда в
+> URL присутствует параметр `?smoke=et-008` (или хеш `#smoke=et-008`).
+> Это нужно автоматическим тестам пайплайна — они проверяют, что
+> deploy на test содержит сборку правильного work-item, и что фронтенд
+> отвечает на разметку без падений.
+
+## Уточнения (приняты по умолчанию для smoke)
+
+1. Видимый идентификатор маркера: `#pipeline-smoke`.
+2. Текст маркера (на русском): «ET-008 ✓».
+3. Позиция: левый нижний угол экрана (не конфликтует с
+ `#map-controls-r` справа, с `bottom-sheet` снизу-по центру, с
+ `.maplibregl-ctrl-attrib` справа-внизу). Конкретно — `left: 8px;
+ bottom: 8px`.
+4. Размер: 11px шрифт, нижний регистр, полупрозрачный фон, нейтральный
+ тёмно-серый цвет; не должен закрывать ничего важного даже если
+ как-то стал видимым случайно.
+5. Условие отображения: маркер присутствует в DOM **всегда**, но имеет
+ `display: none` по умолчанию. Видим становится, когда у ``
+ есть класс `smoke-mode`. Класс ставится автоматически инлайн-скриптом
+ в ``, если `location.search` содержит `smoke=et-008` ИЛИ
+ `location.hash` содержит `smoke=et-008`.
+6. Не использовать `localStorage`. Маркер ничего не сохраняет —
+ только реагирует на URL текущего хита.
+7. Доступность: `aria-hidden="true"`, `role="presentation"` — маркер
+ технический, не должен попадать в screen reader.
+8. Семантика body-класса: имя `smoke-mode` зарезервировано **только**
+ за этим work item. Если в будущем понадобятся аналогичные маркеры
+ для других work items — расширяем семантику тем же классом, но с
+ дополнительными data-атрибутами.
+9. Backend / БД / тайл-эндпоинты / OSRM / app.js / units.js / gpx.js
+ **не затрагиваются**.
+10. Тёмная и светлая темы: маркер использует одинаковые цвета в обеих
+ темах (тёмный фон + светлый текст), читаемость гарантируется
+ собственными цветами, а не наследованием от темы.
diff --git a/docs/work-items/ET-008/01-brd.md b/docs/work-items/ET-008/01-brd.md
new file mode 100644
index 0000000..11be77e
--- /dev/null
+++ b/docs/work-items/ET-008/01-brd.md
@@ -0,0 +1,120 @@
+---
+type: brd
+work_item_id: ET-008
+title: "BRD: Smoke test analyst integration"
+version: 1
+status: draft
+created_at: 2026-05-31
+updated_at: 2026-05-31
+authors:
+ - "agent:analyst"
+---
+
+# BRD — ET-008: Smoke test analyst integration
+
+## 1. Цель
+
+Подтвердить, что цепочка агентов `analyst → architect → coder → tester`
+работоспособна **end-to-end**: аналитик выдаёт валидные артефакты,
+архитектор по ним строит план, кодер минимально его реализует,
+тестировщик прогоняет автотесты (включая Playwright) и автоматически
+закрывает задачу.
+
+Полезной фичи для конечного пользователя нет — это намеренно
+технический smoke. Минимальное изменение во фронтенде нужно лишь как
+«отпечаток сборки», который Playwright увидит и подтвердит.
+
+## 2. Контекст
+
+- Веб-приложение: MapLibre GL JS 4.7 + vanilla JS, без фреймворка.
+- Базовая страница: `src/web/index.html`; стили — `src/web/app.css`;
+ логика — `src/web/app.js` (НЕ ТРОГАТЬ в рамках ET-008).
+- ET-007 (Спутниковая карта) уже использовал такую же idea-pipeline
+ для dry-run; ET-008 — следующая итерация, ещё минимальнее: ноль JS,
+ ноль внешних зависимостей, ноль localStorage.
+- Имеется работающая Playwright-инфра (`tests/web/e2e/`), которая
+ умеет открывать тест-окружение и снимать скриншоты.
+
+## 3. Scope
+
+### In scope
+
+| # | Функция |
+|------|------------------------------------------------------------------------------------------------------|
+| F-01 | DOM-элемент `#pipeline-smoke` с текстом «ET-008 ✓» в `src/web/index.html` |
+| F-02 | CSS-правила для `#pipeline-smoke` в `src/web/app.css` (скрыт по умолчанию) |
+| F-03 | CSS-правила для `body.smoke-mode #pipeline-smoke` (видим в smoke-режиме) |
+| F-04 | Инлайн-скрипт в `` `src/web/index.html`, добавляющий `smoke-mode` к `` по URL-условию |
+| F-05 | Условие активации: `location.search.includes('smoke=et-008')` ИЛИ `location.hash.includes('smoke=et-008')` |
+| F-06 | По умолчанию (без параметра) маркер физически в DOM, но `display:none` |
+| F-07 | Маркер `aria-hidden="true"` / `role="presentation"` — не попадает в screen reader |
+| F-08 | Позиционирование: `position: fixed; left: 8px; bottom: 8px; z-index` ниже sheets/popup'ов |
+| F-09 | Совместимость с тёмной и светлой темами — собственные цвета, не наследует темовые переменные |
+
+### Out of scope
+
+- JavaScript-логика в `src/web/app.js`, `units.js`, `gpx.js`.
+- Любой backend / БД / OSRM / тайлы.
+- Сохранение состояния (localStorage / sessionStorage / cookies).
+- Видимость по нажатию кнопки / shortcut'у клавиатуры / тапу — только URL.
+- Локализация (текст «ET-008 ✓» одинаков для всех языков).
+- Анимации появления / скрытия.
+- Управление через query API (REST/IPC).
+- Мобильный layout-tuning (маркер одинаков на desktop и mobile).
+- Любые другие work item identifiers, кроме `et-008`.
+
+## 4. Метрики успеха
+
+| Метрика | Критерий |
+|-----------------------------------------------|-----------------------------------------------------------------------------------------|
+| Наличие маркера в DOM | На любой загрузке `document.querySelector('#pipeline-smoke')` не null |
+| Скрытость по умолчанию | На `?` (без параметра) `getComputedStyle(...).display === 'none'` |
+| Видимость в smoke-режиме | На `?smoke=et-008` или `#smoke=et-008` маркер визуально различим в левом нижнем углу |
+| Контент маркера | `textContent.trim() === 'ET-008 ✓'` |
+| Корректность ARIA | `aria-hidden="true"`, `role="presentation"` |
+| Отсутствие конфликтов | Маркер не перекрывает `#map-controls-r`, sheets, `.maplibregl-ctrl-attrib` |
+| Стабильность тем | После `toggleTheme()` маркер остаётся видим/скрыт согласно своему правилу |
+| Отсутствие регрессий | Все существующие E2E (ET-001..ET-007) остаются зелёными |
+| Время от клика до отображения | После загрузки страницы маркер показан **до** `DOMContentLoaded` end (инлайн-скрипт) |
+| Отсутствие сетевых запросов | ET-008 не порождает ни одного нового HTTP-запроса |
+| Откатываемость | Полный откат — 3 диффа (HTML head + HTML body + CSS блок), 1 коммит |
+
+## 5. Риски
+
+| Риск | Вероятность | Влияние | Митигация |
+|---------------------------------------------------------------------|-------------|---------|------------------------------------------------------------------------------------|
+| Инлайн-скрипт в `` ломает CSP | Низкая | Среднее | CSP не настроен сейчас. Если когда-то будет — переключить на data-атрибут + CSS-only|
+| `#pipeline-smoke` перекрывает важный UI (например `.maplibregl-ctrl-scale`) | Низкая | Низкое | `z-index: 1` — ниже всех плавающих контролов; позиция фиксирована подальше |
+| Маркер случайно засветился пользователю (например shared link с `?smoke=et-008`) | Низкая | Низкое | Текст нейтральный, не раскрывает ничего внутреннего; стиль ненавязчивый |
+| Body-класс `smoke-mode` конфликтует с будущим классом темы | Низкая | Низкое | Префикс `smoke-` зарезервирован; в проекте сейчас нет похожих имён |
+| ARIA-атрибуты «protect» сломаются при mutation observer на body | Низкая | Низкое | `aria-hidden` ставится статически в HTML, не из JS |
+| Маркер ломает Playwright-снимки других тестов | Низкая | Низкое | По умолчанию `display:none` — на скриншоте не виден, BB-rect = 0 |
+| Лишний div снижает производительность DOM | Очень низкая| Очень низкое| 1 элемент, без подписок, без обработчиков |
+| Старые браузеры не поддерживают `includes` на строках | Очень низкая| Низкое | `String.prototype.includes` — ES2015, поддержано во всех целевых браузерах |
+
+## 6. Зависимости
+
+- **Внешние сервисы**: нет.
+- **Внутренние**: только `src/web/index.html`, `src/web/app.css`.
+- Не зависит от ET-005 / ET-006 / ET-007.
+- Не блокирует ни одну фазу (PH-1..PH-9).
+- Не вносит изменений в `app.js`, `units.js`, `gpx.js`.
+- Не меняет `style.json`, `style-dark.json`.
+- Backend, БД, OSRM, миграции, контейнеры — не затрагиваются.
+- CI/CD — не меняется. Только новые E2E-тесты для самого маркера в
+ `tests/web/e2e/pipeline-smoke.spec.ts`.
+
+## 7. Критерии smoke-успеха (для пайплайна)
+
+Эта работа считается завершённой, когда:
+
+1. Все 5 артефактов аналитика (`00`..`04b`) присутствуют и валидны.
+2. Архитектор выдаёт минимум один план в `05-architecture.md` или
+ эквивалент.
+3. Кодер вносит изменения только в `src/web/index.html` +
+ `src/web/app.css` (по diff'у видно).
+4. Все тесты UT/IT/E2E зелёные на test-окружении.
+5. Tester автоматически закрывает задачу.
+
+Само наличие зелёного smoke-прогона важнее, чем визуальная
+эстетика маркера.
diff --git a/docs/work-items/ET-008/02-trz.md b/docs/work-items/ET-008/02-trz.md
new file mode 100644
index 0000000..8e50570
--- /dev/null
+++ b/docs/work-items/ET-008/02-trz.md
@@ -0,0 +1,281 @@
+---
+type: trz
+work_item_id: ET-008
+title: "ТЗ: Smoke test analyst integration"
+version: 1
+status: draft
+created_at: 2026-05-31
+updated_at: 2026-05-31
+authors:
+ - "agent:analyst"
+depends_on:
+ - "ET-008/01-brd.md"
+---
+
+# Техническое задание — ET-008: Smoke test analyst integration
+
+## 1. Общая архитектура изменений
+
+Изменение строго фронтовое и максимально минимальное. Затрагиваются
+**ровно два файла**:
+
+- `src/web/index.html`
+ - В `` добавить инлайн-скрипт, который выставляет
+ `document.body.classList.add('smoke-mode')`, если в URL присутствует
+ `smoke=et-008` (в `search` или `hash`).
+ - В `` (рядом с `
` или сразу перед ``)
+ добавить элемент `
ET-008 ✓
`.
+- `src/web/app.css`
+ - В конец файла добавить блок с правилами для `#pipeline-smoke`.
+
+**Запрещено** трогать: `src/web/app.js`, `src/web/units.js`,
+`src/web/gpx.js`, `src/web/style.json`, `src/web/style-dark.json`,
+`src/api/**`, `tests/api/**`, миграции, Docker-конфигурацию.
+
+## 2. Функциональные требования
+
+### REQ-F-01. DOM-маркер `#pipeline-smoke`
+
+В `src/web/index.html` добавить элемент:
+
+```html
+
ET-008 ✓
+```
+
+Размещение: после `` (т.е. внутри ``,
+сразу после карты), но **до** ``. Конкретное место —
+после блока `
` или эквивалентного места,
+где сейчас лежат «свободно плавающие» элементы (`#ruler-toast`,
+`#app-toast`).
+
+Текст узла: ровно `ET-008 ✓` (без кавычек, с одним пробелом перед
+галочкой, U+2713 CHECK MARK).
+
+### REQ-F-02. Инлайн-скрипт активации в ``
+
+В `` `src/web/index.html`, **после** ``
+и **до** закрывающего ``, добавить:
+
+```html
+
+```
+
+Замечания:
+- Скрипт ставит класс на `` (`documentElement`), а не на
+ ``, потому что на момент выполнения (в ``) ``
+ ещё не существует. Эквивалентный селектор для CSS —
+ `html.smoke-mode #pipeline-smoke`. Это требование к CSS-блоку
+ (см. REQ-F-04).
+- `try/catch` обязателен — если по какой-то причине `location`
+ не доступен (тест с jsdom без URL), скрипт не должен ронять
+ страницу.
+- Скрипт **синхронный**, не модуль, без `defer`/`async` — он
+ должен сработать до того, как CSS попытается применить
+ `display:none` к видимому в smoke маркеру (избежать FOUC).
+
+### REQ-F-03. CSS базовое состояние (скрыт)
+
+В конец `src/web/app.css` добавить:
+
+```css
+/* ── ET-008: pipeline smoke marker ───────────────────────────
+ По умолчанию полностью скрыт. Включается классом .smoke-mode
+ на , который ставит инлайн-скрипт в , если
+ в URL присутствует ?smoke=et-008 или #smoke=et-008.
+ ──────────────────────────────────────────────────────────── */
+#pipeline-smoke {
+ display: none;
+}
+```
+
+### REQ-F-04. CSS активное состояние (видим)
+
+Сразу после REQ-F-03 в `src/web/app.css`:
+
+```css
+html.smoke-mode #pipeline-smoke {
+ display: inline-block;
+ position: fixed;
+ left: 8px;
+ bottom: 8px;
+ z-index: 1;
+ padding: 2px 6px;
+ font: 11px/1.4 system-ui, -apple-system, sans-serif;
+ color: #e7e7e7;
+ background: rgba(20, 20, 28, 0.7);
+ border-radius: 4px;
+ pointer-events: none;
+ user-select: none;
+ letter-spacing: 0.02em;
+}
+```
+
+Значения цвета и фона **не зависят** от темы — это намеренно, чтобы
+маркер был стабильно читаем и в светлой, и в тёмной теме без отдельных
+правил `body.theme-dark`.
+
+### REQ-F-05. Условие активации
+
+Маркер показывается, если **любое** из условий выполнено:
+
+- `location.search` (часть URL после `?`) содержит подстроку
+ `smoke=et-008`;
+- `location.hash` (часть URL после `#`) содержит подстроку
+ `smoke=et-008`.
+
+Сравнение **точное**, чувствительно к регистру. Любое отклонение
+(`smoke=ET-008`, `smoke=et_008`, `smoke=et-007`, `smoketest=et-008`)
+**не** активирует маркер.
+
+### REQ-F-06. Не-конфликтность с темами
+
+После `toggleTheme()` маркер:
+- если был видим (smoke-mode) — остаётся видимым с теми же цветами;
+- если был скрыт (no smoke-mode) — остаётся скрытым.
+
+То есть body-класс `theme-dark` не влияет на отображение
+`#pipeline-smoke`.
+
+### REQ-F-07. Не-конфликтность с layout
+
+`z-index: 1` ниже, чем у `#map-controls-r` (фактический z-index у
+существующих контролов — выше). Маркер не должен:
+- перекрывать `#map-controls-r` (top-right);
+- перекрывать `.maplibregl-ctrl-attrib` (bottom-right);
+- мешать `#toolbar` на мобильном (нижняя панель);
+- перекрывать любой `.bottom-sheet`, когда тот открыт.
+
+В частности на мобильном бутылочное горлышко — `#toolbar` снизу.
+Маркер в `left: 8px; bottom: 8px` помещается слева, тулбар обычно
+центрирован/растянут, так что небольшой риск перекрытия допустим,
+но визуально не критичен (маркер маленький и полупрозрачный).
+
+### REQ-F-08. ARIA
+
+- `aria-hidden="true"` — обязательно.
+- `role="presentation"` — обязательно.
+- Никаких подсказок (`title`), `aria-label`, фокусируемых элементов
+ внутри.
+
+### REQ-F-09. Отсутствие сетевых эффектов
+
+Реализация не должна:
+- добавлять `` / `