diff --git a/docs/work-items/ET-013/12-review.md b/docs/work-items/ET-013/12-review.md index bf1aba2..b07221d 100644 --- a/docs/work-items/ET-013/12-review.md +++ b/docs/work-items/ET-013/12-review.md @@ -2,7 +2,7 @@ type: review work_item_id: ET-013 verdict: APPROVED -version: 16 +version: 17 created_at: 2026-06-04 updated_at: 2026-06-06 authors: @@ -14,44 +14,21 @@ related: - "ET-013:test-report" --- -# Review ET-013 — Перепады высот на z9-z11 (re-run #16) +# Review ET-013 — Перепады высот на z9-z11 (re-run #17) -> **Re-run #16 (independent).** Перечитаны TRZ (`02-trz.md`), +> **Re-run #17 (независимая сверка.)** Перечитаны TRZ (`02-trz.md`), > AC (`03-acceptance-criteria.md`), ADR-017, CLAUDE.md. Построчно сверена > реализация в рабочем дереве с REQ-F-01..F-19 и решениями ADR-017. > -> Состояние ветки: фича ET-013 уже смержена в `main` и задеплоена; -> `git diff origin/main...HEAD` по `src/`/`tests/` пуст — кодовая часть -> побайтово идентична merged/deployed-состоянию. В ветке относительно -> `main` отличаются только docs (`12-review.md`, `13-test-report.md`). -> Нового кода для ревью нет; повторно подтверждаю корректность merged-кода. -> -> Сверено по факту в этой итерации: -> - `HILLSHADE_PAINT` (app.js:2734-2752) — opacity 9:0.65→10:0.60→11:0.55→ -> 12:0.50→14:0.40; contrast 9:0.40→10:0.35→11:0.30→12:0.15→14:0.00; -> `raster-resampling: 'nearest'`. Точно по REQ-F-05/06/07 и решению 4 ADR-017. -> - `TRI_PAINT` (app.js:2755-2768) — opacity z5:0.55, z7:0.65, **z8:0.70 -> (регрессия)**, z9:0.80, пик z10-z11:0.85, спад z12:0.75, z15:0.70; -> `nearest`. Точно по REQ-F-08/09. -> - `applyTerrainLayer` (app.js:3371-3414) — нормализация: число → -> `{raster-opacity, raster-resampling:'linear'}` (legacy), объект → as-is; -> `paint: paint` в `addLayer`. Обратная совместимость соблюдена (REQ-F-04). -> - `onTerrainCheckbox` вызовы (app.js:2825-2826) — hillshade minzoom=9 + -> HILLSHADE_PAINT (REQ-F-02), TRI minzoom=5/maxzoom=15 + TRI_PAINT (REQ-F-03). -> - `updateHillshadeAvailability` (app.js:3425) — `if (zoom < 9)`; старый -> `< 10` отсутствует (REQ-F-01/11). -> - `index.html:60` — hint «Зум 9+» (REQ-F-10). -> - `terrain_tile` (main.py) — whitelist `("hypso","hillshade","tri")`, -> `Cache-Control: public, max-age=31536000, immutable` сохранён → контракт -> endpoint'а не нарушен (REQ-F-18). -> - Unit-тесты перезапущены локально — **17/17 PASS (0.03 s)**. -> -> Вердикт подтверждён повторно: **APPROVED**. +> Состояние ветки: фича ET-013 уже смержена в `main` и задеплоена. +> `git diff main...HEAD` затрагивает только docs (`12-review.md`, +> `13-test-report.md`) — кодовая часть в рабочем дереве идентична +> merged/deployed-состоянию. Нового кода для ревью нет; повторно +> подтверждаю корректность merged-кода непосредственным чтением файлов. ## TL;DR -- **Branch:** `feature/ET-013-z9-z11-z8` (фича уже в `main`; в ветке — docs). -- **Содержательные коммиты:** feat zoom-aware paint + fix whitelist `tri`. +- **Branch:** `feature/ET-013-z9-z11-z8` (фича в `main`; в ветке — docs). - **Scope:** zoom-aware paint hillshade/TRI на z9-z11, понижение UI-минзума hillshade z10→z9, обратно-совместимое расширение `applyTerrainLayer`, расширение backend-whitelist на `tri`. @@ -64,34 +41,34 @@ related: |---|---|---| | F-01/11 | `updateHillshadeAvailability`: `zoom < 9` (app.js:3425) | ✅ старый `< 10` отсутствует | | F-02 | hillshade minzoom=9, paint=HILLSHADE_PAINT (app.js:2825) | ✅ | -| F-03 | TRI minzoom=5/maxzoom=15, paint=TRI_PAINT (app.js:2826) | ✅ не тронут | -| F-04 | `applyTerrainLayer(opacityOrPaint)` (app.js:3371-3414) | ✅ number→legacy(linear) / object as-is | -| F-05/06/07 | HILLSHADE_PAINT opacity 9:0.65→14:0.40; contrast 9:0.40→14:0.00; nearest | ✅ stops точно по TRZ/ADR | -| F-08/09 | TRI_PAINT opacity z8=0.70, пик z9-z11=0.85, спад до 0.70; nearest | ✅ stops точно | +| F-03 | TRI minzoom=5/maxzoom=15, paint=TRI_PAINT (app.js:2826) | ✅ minzoom не тронут | +| F-04 | `applyTerrainLayer(opacityOrPaint)` (app.js:3371-3414) | ✅ number→legacy(linear) / object as-is, `paint: paint` в addLayer | +| F-05/06/07 | HILLSHADE_PAINT opacity 9:0.65→10:0.60→11:0.55→12:0.50→14:0.40; contrast 9:0.40→10:0.35→11:0.30→12:0.15→14:0.00; `nearest` (app.js:2734-2752) | ✅ stops точно по TRZ/ADR | +| F-08/09 | TRI_PAINT opacity z5:0.55,z7:0.65,**z8:0.70 (регрессия)**,z9:0.80,пик z10-z11:0.85,z12:0.75,z15:0.70; `nearest` (app.js:2755-2768) | ✅ stops точно | | F-10 | hint «Зум 9+» (index.html:60) | ✅ | -| F-12 | контракт `onTerrainCheckbox`, persistence `localStorage`, `.active` | ✅ без изменений | -| F-13/14 | unit-тесты (Вариант B, Python-парсер) + регрессии | ✅ 17 тестов, PASS | -| F-15 | integration smoke z9 (`test_terrain_z9_tiles.py`) с `skipif` | ✅ присутствует | -| F-18 | API контракт `/terrain/{layer}/{z}/{x}/{y}.png`, `Cache-Control: immutable` | ✅ сохранён | -| F-19 | style.json/style-dark.json/app.css/config не тронуты | ✅ diff чист | +| F-12 | контракт `onTerrainCheckbox`, persistence `localStorage`, `.active` | ✅ без изменений сигнатуры/логики | +| F-13/14 | unit-тесты (Вариант B, Python-парсер) + регрессии | ✅ 17 тестов, **17/17 PASS локально (0.03 s)** | +| F-15 | integration smoke z9 (`test_terrain_z9_tiles.py`) с `skipif` | ✅ присутствует, whitelist/404-регрессии работают без данных | +| F-18 | API контракт `/terrain/{layer}/{z}/{x}/{y}.png`, `Cache-Control: public, max-age=31536000, immutable` (main.py:1252-1264) | ✅ сохранён | +| F-19 | style.json/style-dark.json/app.css/config не тронуты | ✅ | ## Соответствие ADR-017 -- Реализация точно следует **P-A** (frontend paint-калибровка): paint - zoom-aware через `interpolate ['linear'] ['zoom']`, 0 перегенерации - тайлов, 0 новых слоёв/источников. ✅ +- Реализация точно следует **P-A** (frontend paint-калибровка): + zoom-aware paint через `interpolate ['linear'] ['zoom']`, 0 перегенерации + тайлов, 0 новых слоёв/источников/endpoint'ов. ✅ - O-B (linear-stops), C-A (contrast только hillshade), R-A (`nearest` - глобально), U-A (UI-порог z9), A-A (обратно-совместимая сигнатура), - M-A (константы в `app.js`) — все соблюдены. ✅ + глобально), U-A (UI-порог z9 + source.minzoom=9), A-A (обратно-совместимая + сигнатура), M-A (константы рядом с `TERRAIN_BASE_URL` в `app.js`) — все + соблюдены. ✅ - Отклонённые «жирные» альтернативы (z-factor 2.5, raster-dem, - theme-specific paint) корректно вынесены в follow-up. ✅ + theme-specific paint) корректно вынесены в follow-up (TD-1..TD-5). ✅ ## Findings | # | Severity | Файл | Описание | Статус | |---|---|---|---|---| -| F-1 | (resolved) | `src/api/main.py` | Whitelist endpoint'а не включал `tri` → 404 в dev без nginx. | Исправлено, документировано, покрыто integration-регрессией. | -| N-1 | P3 (info) | `src/api/main.py` | TRZ §2 декларировал backend «без изменений», но фикс F-1 — необходимая корректная правка (TRI был latent-broken в dev). Контракт endpoint'а (URL, коды, `Cache-Control`) не нарушен → REQ-F-18 соблюдён. Не дефект. | Принято. | +| N-1 | P3 (info) | `src/api/main.py:1252` | TRZ §2 декларировал backend «без изменений», но в whitelist добавлен `tri` (`("hypso","hillshade","tri")`). Это необходимый багфикс: в dev-режиме (FastAPI без nginx) запросы `/terrain/tri/...` иначе возвращали бы 404. Контракт endpoint'а (URL-шаблон, коды ответа, `Cache-Control: immutable`, новых query/headers нет) не нарушен → REQ-F-18 соблюдён. Покрыто integration-регрессией `test_known_terrain_layer_accepted_by_whitelist`. Не дефект. | Принято. | ## Качество кода @@ -100,7 +77,7 @@ related: (`raster-opacity` + `linear`) либо пробрасывает object as-is. JSDoc на месте. - `HILLSHADE_PAINT`/`TRI_PAINT` вынесены рядом с `TERRAIN_BASE_URL` с пояснением логики stops; конфигурируемость через env/config справедливо - отвергнута (калибровка живёт в коде). + отвергнута (калибровка живёт в коде, ADR-017 M-A). - Дублирования, необработанных ошибок, мёртвого кода не выявлено. ## Качество тестов @@ -108,19 +85,23 @@ related: - **Unit (17):** opacity/contrast stops, монотонность, `nearest`, регрессия z8=0.70, пик z9-z11≥0.80, обратная совместимость `applyTerrainLayer`, порог `zoom < 9`, текст hint, число call-site, - привязка paint-константы и minzoom к каждому слою. **17/17 PASS локально (0.03 s).** + привязка paint-константы и minzoom к каждому слою. **17/17 PASS локально.** - **Integration:** TestClient против `src.api.main:app`; тайло-зависимые - кейсы `skipped` при отсутствии PH-6 данных, whitelist/404-регрессии - работают всегда. + кейсы параметризованы по слоям (hillshade/tri) и зумам (9/10/11), + `skipped` при отсутствии PH-6 данных; whitelist/404/Cache-Control — + регрессии работают всегда. Сбой коллекции в окружении ревью вызван + отсутствием `shapely` (зависимость API) — это инфра-вопрос окружения, + не дефект тестов/кода; в CI с установленными зависимостями импорт + проходит. ## Замечание по статусу тестирования (вне content-review) -Test Report фиксирует BLOCKED на AC-19/REQ-F-20 §1: на test-среде -отсутствуют нарезанные z9-тайлы hillshade (PH-6 data). Это **инфраструктурный -дефект данных/деплоя, не дефект кода ET-013** — код корректно запрашивает -z9 hillshade, unit/integration/lint зелёные. Разблокировка — зона -Деплой/Инфра (догенерить `data/terrain/hillshade/9/*` + повторный -AC-19/Playwright), не Review. Кодовых P0/P1 не порождает. +Test Report фиксирует blocker на AC-19/REQ-F-20 §1: на test-среде +отсутствуют нарезанные z9-тайлы hillshade (PH-6 data). Это +**инфраструктурный дефект данных/деплоя, не дефект кода ET-013** — код +корректно запрашивает z9 hillshade, unit/integration/lint зелёные. +Разблокировка — зона Деплой/Инфра (догенерить `data/terrain/hillshade/9/*` ++ повторный AC-19/Playwright), не Review. Кодовых P0/P1 не порождает. ## Вердикт