Compare commits

...

42 Commits

Author SHA1 Message Date
3fcda9203e tester(ET): auto-commit from tester run_id=261
Some checks failed
CI / lint (push) Failing after 5s
CI / test (push) Successful in 9s
CI / build (push) Has been skipped
2026-06-07 01:41:56 +00:00
7f0e10c9f5 reviewer(ET): auto-commit from reviewer run_id=260
All checks were successful
CI / lint (push) Successful in 4s
CI / test (push) Successful in 10s
CI / build (push) Successful in 2s
2026-06-07 01:38:35 +00:00
67c65db3de tester(ET): auto-commit from tester run_id=259
All checks were successful
CI / lint (push) Successful in 5s
CI / test (push) Successful in 10s
CI / build (push) Successful in 2s
2026-06-07 01:36:23 +00:00
e75a823996 reviewer(ET): auto-commit from reviewer run_id=258
All checks were successful
CI / lint (push) Successful in 4s
CI / test (push) Successful in 10s
CI / build (push) Successful in 2s
2026-06-07 01:33:50 +00:00
bcffbd1f5a reviewer(ET): auto-commit from reviewer run_id=256
All checks were successful
CI / lint (push) Successful in 4s
CI / test (push) Successful in 9s
CI / build (push) Successful in 2s
2026-06-07 01:16:19 +00:00
4e28729d13 tester(ET): auto-commit from tester run_id=255
All checks were successful
CI / lint (push) Successful in 4s
CI / test (push) Successful in 8s
CI / build (push) Successful in 2s
2026-06-07 01:13:13 +00:00
d179035809 reviewer(ET): auto-commit from reviewer run_id=254
All checks were successful
CI / lint (push) Successful in 4s
CI / test (push) Successful in 9s
CI / build (push) Successful in 2s
2026-06-07 01:10:58 +00:00
c3dea44e7d tester(ET): auto-commit from tester run_id=253
All checks were successful
CI / lint (push) Successful in 4s
CI / test (push) Successful in 8s
CI / build (push) Successful in 2s
2026-06-07 01:09:04 +00:00
0390345c92 reviewer(ET): auto-commit from reviewer run_id=252
All checks were successful
CI / lint (push) Successful in 5s
CI / test (push) Successful in 9s
CI / build (push) Successful in 2s
2026-06-07 01:05:03 +00:00
857a76bb48 tester(ET): auto-commit from tester run_id=251
All checks were successful
CI / lint (push) Successful in 4s
CI / test (push) Successful in 9s
CI / build (push) Successful in 2s
2026-06-07 01:01:53 +00:00
c29c5b0aab reviewer(ET): auto-commit from reviewer run_id=250
All checks were successful
CI / lint (push) Successful in 4s
CI / test (push) Successful in 9s
CI / build (push) Successful in 2s
2026-06-07 00:57:53 +00:00
d0c6633567 reviewer(ET): auto-commit from reviewer run_id=248
All checks were successful
CI / lint (push) Successful in 4s
CI / test (push) Successful in 9s
CI / build (push) Successful in 2s
2026-06-07 00:40:42 +00:00
b99e3adfdd reviewer(ET): auto-commit from reviewer run_id=246
All checks were successful
CI / lint (push) Successful in 4s
CI / test (push) Successful in 9s
CI / build (push) Successful in 3s
2026-06-07 00:22:08 +00:00
61640518bd tester(ET): auto-commit from tester run_id=245
All checks were successful
CI / lint (push) Successful in 4s
CI / test (push) Successful in 9s
CI / build (push) Successful in 2s
2026-06-07 00:19:33 +00:00
6b52595fa8 reviewer(ET): auto-commit from reviewer run_id=244
All checks were successful
CI / lint (push) Successful in 5s
CI / test (push) Successful in 9s
CI / build (push) Successful in 2s
2026-06-07 00:16:27 +00:00
efd3ca5b3f tester(ET): auto-commit from tester run_id=243
All checks were successful
CI / lint (push) Successful in 5s
CI / test (push) Successful in 10s
CI / build (push) Successful in 2s
2026-06-07 00:14:13 +00:00
b025c43213 reviewer(ET): auto-commit from reviewer run_id=242
All checks were successful
CI / lint (push) Successful in 5s
CI / test (push) Successful in 10s
CI / build (push) Successful in 2s
2026-06-07 00:10:41 +00:00
f82bb8cc0e reviewer(ET): auto-commit from reviewer run_id=240
All checks were successful
CI / lint (push) Successful in 4s
CI / test (push) Successful in 9s
CI / build (push) Successful in 2s
2026-06-06 23:55:18 +00:00
ea00b7e3ff reviewer(ET): auto-commit from reviewer run_id=238
All checks were successful
CI / lint (push) Successful in 4s
CI / test (push) Successful in 9s
CI / build (push) Successful in 2s
2026-06-06 23:39:52 +00:00
c4ea3f3196 tester(ET): auto-commit from tester run_id=237
All checks were successful
CI / lint (push) Successful in 4s
CI / test (push) Successful in 10s
CI / build (push) Successful in 2s
2026-06-06 23:38:01 +00:00
ac4140e5e0 reviewer(ET): auto-commit from reviewer run_id=236
All checks were successful
CI / lint (push) Successful in 4s
CI / test (push) Successful in 10s
CI / build (push) Successful in 3s
2026-06-06 23:34:15 +00:00
5b3961c0f5 tester(ET): auto-commit from tester run_id=235
All checks were successful
CI / lint (push) Successful in 4s
CI / test (push) Successful in 9s
CI / build (push) Successful in 2s
2026-06-06 23:32:20 +00:00
786e4e75e9 reviewer(ET): auto-commit from reviewer run_id=234
All checks were successful
CI / lint (push) Successful in 4s
CI / test (push) Successful in 9s
CI / build (push) Successful in 2s
2026-06-06 23:27:23 +00:00
79f5b93ed2 tester(ET): auto-commit from tester run_id=233
All checks were successful
CI / lint (push) Successful in 4s
CI / test (push) Successful in 9s
CI / build (push) Successful in 2s
2026-06-06 23:24:55 +00:00
dd7e1bf021 reviewer(ET): auto-commit from reviewer run_id=232
All checks were successful
CI / lint (push) Successful in 4s
CI / test (push) Successful in 9s
CI / build (push) Successful in 2s
2026-06-06 23:22:14 +00:00
4153b5bcd0 reviewer(ET): auto-commit from reviewer run_id=230
All checks were successful
CI / lint (push) Successful in 4s
CI / test (push) Successful in 9s
CI / build (push) Successful in 3s
2026-06-06 23:06:51 +00:00
d2265fb368 tester(ET): auto-commit from tester run_id=229
All checks were successful
CI / lint (push) Successful in 4s
CI / test (push) Successful in 9s
CI / build (push) Successful in 2s
2026-06-06 23:04:44 +00:00
78f74db872 reviewer(ET): auto-commit from reviewer run_id=228
Some checks failed
CI / test (push) Failing after 4s
CI / lint (push) Successful in 4s
CI / build (push) Has been skipped
2026-06-06 23:02:27 +00:00
a898eef7c9 reviewer(ET): auto-commit from reviewer run_id=226
All checks were successful
CI / lint (push) Successful in 4s
CI / test (push) Successful in 9s
CI / build (push) Successful in 2s
2026-06-06 22:48:04 +00:00
ad6c5a4cee tester(ET): auto-commit from tester run_id=225
All checks were successful
CI / lint (push) Successful in 5s
CI / test (push) Successful in 10s
CI / build (push) Successful in 2s
2026-06-06 22:45:54 +00:00
7866174d8a reviewer(ET): auto-commit from reviewer run_id=224
All checks were successful
CI / lint (push) Successful in 4s
CI / test (push) Successful in 10s
CI / build (push) Successful in 2s
2026-06-06 22:43:36 +00:00
fb90ad9090 tester(ET): auto-commit from tester run_id=223
All checks were successful
CI / lint (push) Successful in 4s
CI / test (push) Successful in 8s
CI / build (push) Successful in 2s
2026-06-06 22:41:41 +00:00
4bb160d85a reviewer(ET): auto-commit from reviewer run_id=222
All checks were successful
CI / lint (push) Successful in 4s
CI / test (push) Successful in 9s
CI / build (push) Successful in 2s
2026-06-06 22:38:57 +00:00
498c7e191d tester(ET): auto-commit from tester run_id=221
All checks were successful
CI / lint (push) Successful in 4s
CI / test (push) Successful in 9s
CI / build (push) Successful in 2s
2026-06-06 22:36:01 +00:00
c9da18fdd0 reviewer(ET): auto-commit from reviewer run_id=220
All checks were successful
CI / lint (push) Successful in 5s
CI / test (push) Successful in 10s
CI / build (push) Successful in 2s
2026-06-06 22:32:45 +00:00
23cd31dbf1 tester(ET): auto-commit from tester run_id=217
All checks were successful
CI / lint (push) Successful in 4s
CI / test (push) Successful in 9s
CI / build (push) Successful in 2s
2026-06-06 22:14:26 +00:00
89b83e3dfb reviewer(ET): auto-commit from reviewer run_id=216
All checks were successful
CI / lint (push) Successful in 5s
CI / test (push) Successful in 9s
CI / build (push) Successful in 2s
2026-06-06 22:11:44 +00:00
fd0c7a47f0 tester(ET): auto-commit from tester run_id=215
All checks were successful
CI / lint (push) Successful in 4s
CI / test (push) Successful in 9s
CI / build (push) Successful in 2s
2026-06-06 22:09:18 +00:00
e948861775 reviewer(ET): auto-commit from reviewer run_id=214
All checks were successful
CI / lint (push) Successful in 5s
CI / test (push) Successful in 9s
CI / build (push) Successful in 2s
2026-06-06 22:06:21 +00:00
0ad44b5341 reviewer(ET): auto-commit from reviewer run_id=211
All checks were successful
CI / lint (push) Successful in 5s
CI / test (push) Successful in 9s
CI / build (push) Successful in 2s
2026-06-06 21:44:56 +00:00
c66d4fbde2 tester(ET): auto-commit from tester run_id=209
All checks were successful
CI / lint (push) Successful in 4s
CI / test (push) Successful in 10s
CI / build (push) Successful in 2s
2026-06-06 21:39:20 +00:00
badd559927 reviewer(ET): auto-commit from reviewer run_id=207
Some checks failed
CI / lint (push) Successful in 5s
CI / test (push) Failing after 5s
CI / build (push) Has been skipped
2026-06-06 21:26:55 +00:00
2 changed files with 1172 additions and 363 deletions

View File

@@ -2,213 +2,116 @@
type: review
work_item_id: ET-013
verdict: APPROVED
version: 2
version: 27
created_at: 2026-06-04
updated_at: 2026-06-04
updated_at: 2026-06-07
authors:
- "agent:reviewer"
related:
- "ET-013:trz"
- "ET-013:adr-017"
- "ET-013:acceptance-criteria"
- "ET-013:test-report"
---
# Review ET-013 — Перепады высот на z9-z11 (re-run #2)
# Review ET-013 — Перепады высот на z9-z11 (re-run #27)
## TL;DR
> **Независимая сверка, свежий экземпляр reviewer.** Перечитаны
> `02-trz.md` (REQ-F-01..F-21), `03-acceptance-criteria.md` (AC-01..AC-22),
> `06-adr/ADR-017-zoom-aware-terrain-paint.md`, `CLAUDE.md`,
> `13-test-report.md` (verdict BLOCKED). Реализация сверена построчно
> с REQ и решениями ADR **прямым чтением файлов рабочего дерева**, без
> доверия предыдущим ревью. Unit-тесты прогнаны локально —
> **17/17 PASS (0.03 s)**.
- **Branch:** `feature/ET-013-z9-z11-z8`
- **Scope:** калибровка клиентского paint для hillshade/TRI на z9-z11
+ понижение UI-минзума hillshade с z10 до z9 + расширение whitelist
backend-endpoint'а на `tri` (фикс по результатам review v1, F-1).
- **HEAD:** `099669d fix(terrain): расширить whitelist endpoint'а на 'tri' (ET-013 review F-1)`
- **Что изменилось со времени review v1:**
- `src/api/main.py:1252` whitelist расширен:
`("hypso", "hillshade") → ("hypso", "hillshade", "tri")` + docstring
с пояснением (см. F-1 v1).
- `tests/integration/test_terrain_z9_tiles.py` параметризован по
`layer = ["hillshade", "tri"]` для z9/z10/z11; добавлен явный
регрессионный тест `test_known_terrain_layer_accepted_by_whitelist`
по всем трём слоям (см. F-2 v1).
- **Тесты:** `pytest tests/unit/test_terrain_paint.py`**17/17 PASS**,
`pytest tests/integration/test_terrain_z9_tiles.py`**6 passed, 7 skipped**
(skip — отсутствие PNG-данных в sandbox, ожидаемо).
- **Verdict: APPROVED.** P0/P1 не найдено. Остались два опциональных
P3 из v1, оба косметика — не блокеры.
## 1. Объём ревью
## Что прочитано
Четыре оси: соответствие ТЗ, соответствие ADR-017, качество кода,
качество тестов. Код фичи слит в `main`; `git diff main...HEAD`
затрагивает только docs (`12-review.md`, `13-test-report.md`). Ревью
выполнено по фактическому состоянию рабочего дерева:
`src/web/app.js`, `src/web/index.html`, `src/api/main.py`,
`tests/unit/test_terrain_paint.py`, `tests/integration/test_terrain_z9_tiles.py`.
- `docs/work-items/ET-013/00-business-request.md`
- `docs/work-items/ET-013/01-brd.md`
- `docs/work-items/ET-013/02-trz.md`
- `docs/work-items/ET-013/03-acceptance-criteria.md`
- `docs/work-items/ET-013/06-adr/ADR-017-zoom-aware-terrain-paint.md`
- `docs/work-items/ET-013/07-infra-requirements.md`
- `docs/work-items/ET-013/12-review.md` v1 (предыдущий вердикт)
- `CLAUDE.md`
- `git diff main...HEAD --stat` (18 файлов, +3911/-14)
- `git diff main...HEAD -- src/api/main.py src/web/app.js src/web/index.html`
- `src/api/main.py:1235-1264` (`terrain_tile` после фикса)
- `src/web/app.js` (диапазоны 2725-2835 и 3356-3430)
- `src/web/index.html:57-65`
- `tests/unit/test_terrain_paint.py`
- `tests/integration/test_terrain_z9_tiles.py`
## 2. Соответствие ТЗ (REQ-F-01..F-21)
## Соответствие ТЗ
| REQ | Что проверено | Статус |
|---|---|---|
| F-01 / F-11 | `updateHillshadeAvailability`: `if (zoom < 9)` (app.js:3425); `< 10` отсутствует | ✅ |
| F-02 | hillshade-вызов `applyTerrainLayer(..., HILLSHADE_PAINT, 9, 15)` (app.js:2825) | ✅ |
| F-03 | TRI-вызов `applyTerrainLayer(..., TRI_PAINT, 5, 15)` — minzoom=5 без изменений (app.js:2826) | ✅ |
| F-04 / F-12 | Сигнатура `applyTerrainLayer(id, tileUrl, enabled, opacityOrPaint, minzoom, maxzoom)`; нормализация `typeof === 'number'` → legacy paint (app.js:3371-3380); `onTerrainCheckbox` + persistence `localStorage` без изменений | ✅ |
| F-05/06/07 | `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; `'nearest'` — дословно по ТЗ | ✅ |
| F-08/09 | `TRI_PAINT` (app.js:2755-2768): opacity 5→0.55,7→0.65,8→0.70,9→0.80,10→0.85,11→0.85,12→0.75,15→0.70; `'nearest'` | ✅ |
| F-10 | `#terrain-hillshade-hint` = «Зум 9+» (index.html:60) | ✅ |
| F-13/14 | `tests/unit/test_terrain_paint.py` — 17 тестов: stops, регрессия z8=0.70, пик z9-z11≥0.80, монотонность, `nearest`, обратная совместимость, порог 9, hint, call-count | ✅ |
| F-15 | `tests/integration/test_terrain_z9_tiles.py` — параметризация по слою/зуму, `skipif` без данных, 404-регрессии независимы от данных | ✅ |
| F-17/F-18/F-19 | persistence без миграции; стили `style.json`/`style-dark.json` и конфиги не тронуты | ✅ |
| Требование | Реализация | Файл / строка | OK |
|---|---|---|---|
| REQ-F-01 — `updateHillshadeAvailability`: порог `zoom < 9` | `if (zoom < 9)` с комментарием ET-013 | `src/web/app.js:3425` | ✅ |
| REQ-F-02 — `source.minzoom = 9` для hillshade | `applyTerrainLayer('terrain-hillshade', …, HILLSHADE_PAINT, 9, 15)` | `src/web/app.js:2825` | ✅ |
| REQ-F-03 — TRI minzoom = 5 без изменений | `applyTerrainLayer('terrain-tri', …, TRI_PAINT, 5, 15)` | `src/web/app.js:2826` | ✅ |
| REQ-F-04 — обратно-совместимое расширение `applyTerrainLayer(opacityOrPaint)` | нормализация `(typeof opacityOrPaint === 'number') ? legacyPaint : opacityOrPaint` | `src/web/app.js:3376-3380` | ✅ |
| REQ-F-05 — HILLSHADE_PAINT `raster-opacity` interpolate по zoom (stops 9/10/11/12/14 → 0.65/0.60/0.55/0.50/0.40) | константа `HILLSHADE_PAINT`, точные stops | `src/web/app.js:2734-2742` | ✅ |
| REQ-F-06 — HILLSHADE_PAINT `raster-contrast` interpolate (stops 9/10/11/12/14 → 0.40/0.35/0.30/0.15/0.00) | присутствует | `src/web/app.js:2743-2750` | ✅ |
| REQ-F-07 — HILLSHADE_PAINT `raster-resampling: 'nearest'` | присутствует | `src/web/app.js:2751` | ✅ |
| REQ-F-08 — TRI_PAINT `raster-opacity` interpolate (z8→0.70, пик z9-z11 = 0.80-0.85) | точное совпадение со spec | `src/web/app.js:2755-2766` | ✅ |
| REQ-F-09 — TRI_PAINT `raster-resampling: 'nearest'` | присутствует | `src/web/app.js:2767` | ✅ |
| REQ-F-10 — hint «Зум 9+» | `<span … id="terrain-hillshade-hint" …>Зум 9+</span>` | `src/web/index.html:60` | ✅ |
| REQ-F-11 — единый порог в `updateHillshadeAvailability` | тот же `< 9` | — | ✅ |
| REQ-F-12 — контракт `onTerrainCheckbox` (localStorage `terrain-hillshade`, `terrain-tri`, `#terrain-toggle.active`) | без изменений | `src/web/app.js:2816-2821` | ✅ |
| REQ-F-13 — unit-тесты paint (Вариант B: Python-парсер) | 17 тестов, все PASS | `tests/unit/test_terrain_paint.py` | ✅ |
| REQ-F-14 — регрессионные тесты (порог 9, hint, callers) | `test_minzoom_threshold_lowered_to_9`, `test_hint_text_updated_to_z9`, `test_apply_terrain_layer_caller_count` | `tests/unit/test_terrain_paint.py` | ✅ |
| REQ-F-15 — integration smoke: `/terrain/{layer}/9/.../….png` → 200 + 404 на невалидный layer + Cache-Control immutable | параметризован по `["hillshade", "tri"]` × `[9, 10, 11]`, регрессии 404, whitelist-тест по 3 слоям | `tests/integration/test_terrain_z9_tiles.py` | ✅ |
| REQ-F-16 — Playwright UI-тесты | в test-плане, исполняет Тестер | — | n/a (review) |
| REQ-F-17 — localStorage без миграции | не тронуто | — | ✅ |
| REQ-F-18 — API-контракт без изменений | сигнатура `GET /terrain/{layer}/{z}/{x}/{y}.png` сохранена; whitelist расширен (см. §«Изменения после v1») | `src/api/main.py:1240-1264` | ✅ |
| REQ-F-19 — конфиги/стили не тронуты | `style.json`, `style-dark.json`, `app.css`, `config/*.yaml` — без правок (`git diff --stat` подтверждает) | — | ✅ |
| REQ-F-20 — pre-deploy curl + smoke | задача deployer'а | — | n/a (review) |
| REQ-F-21 — документация | `00-..-10-` + `06-adr/ADR-017-…` присутствуют | — | ✅ |
ТЗ реализовано полностью и буквально. Все stops paint-выражений
совпадают с REQ-F-05/F-08 до знака.
**Acceptance Criteria.**
- AC-01, AC-02, AC-04, AC-05 (структура paint), AC-15, AC-17, AC-22
(back-compat) — покрыты unit-тестами, **зелёные**.
- AC-16 — integration-тесты структурно корректны, в sandbox skip
из-за отсутствия PNG; whitelist-регрессия по `tri/hillshade/hypso`
работает без данных и зелёная.
- AC-03, AC-06..AC-13, AC-19, AC-21 — требуют test-среды и Playwright,
относятся к этапу Тестирования.
## 3. Соответствие ADR-017
## Соответствие ADR
- **P-A** (frontend paint-калибровка) — ✅ правка во фронтенде, без перегенерации тайлов, без смены paint-pipeline.
- **O-B** (linear interpolate stops) — ✅ stops совпадают с ADR §Решение п.4-5; явная точка `8→0.70` (регрессия AC-06) и clamping на верхнем стопе (регрессия AC-10).
- **C-A** (`raster-contrast` zoom-aware только для hillshade) — ✅, TRI контраст не трогается.
- **R-A** (`'nearest'` глобально для обоих слоёв) — ✅.
- **U-A** (UI-гейт hillshade понижен до z9, не до z8) — ✅.
- **T-A** (единый paint, theme-specific отложен в follow-up ADR-018) — ✅.
- **A-A** (обратно-совместимое расширение `applyTerrainLayer`) — ✅.
- **M-A** (константы рядом с `TERRAIN_BASE_URL` в `app.js`) — ✅.
ADR-017 («Zoom-aware terrain paint») реализован по всем пунктам:
Нарушений ADR нет.
- **P-A** (frontend-only): backend-фикс whitelist'а `tri` — это
**корректная инфра-уточнение**, не выход за P-A. ADR-017 §«Контекст»
утверждал, что эндпоинт уже отдаёт `/terrain/{layer}/…` для TRI;
фактически до этого PR `tri` не был в whitelist'е в dev-режиме, и
фикс восстанавливает заявленное состояние (а не вводит новый
endpoint/source/слой). Документировано в docstring `terrain_tile`.
- **U-A** (UI-минзум 10→9): подтверждено `app.js:3425` и `index.html:60`.
- **A-A** (обратно-совместимое расширение `applyTerrainLayer`):
нормализация числа в legacy-paint реализована (`app.js:3376-3380`),
unit-test `test_apply_terrain_layer_normalizes_number_to_legacy_paint`
зелёный.
- **O-B + C-A + R-A** для HILLSHADE_PAINT: stops, contrast,
`nearest`-resampling — точно по ADR.
- **O-B + R-A** для TRI_PAINT: stops с явной точкой `8→0.70` для
регрессии z8 — точно по ADR.
- **T-A** (один paint на все темы): theme-specific paint не добавлен —
соответствует MVP-решению ADR.
- **M-A** (константы живут в `app.js` рядом с `TERRAIN_BASE_URL`):
подтверждено, расстояние 1 строка.
## 4. Качество кода
Нарушений ADR-017 не найдено.
- `applyTerrainLayer` расширена обратно-совместимо; ветка
`typeof === 'number'` сохраняет старый контракт (`raster-opacity` +
`linear`). Объект paint пробрасывается в `addLayer` как есть.
- Константы paint снабжены комментариями со ссылкой на ADR-017 и
обоснованием stops; магических чисел в логике нет, калибровка
изолирована в декларациях.
- z-order вставки слоя (`firstTrailLayer`) сохранён; дублирования и
мёртвого кода нет.
## Изменения после review v1 (что было исправлено)
## 5. Качество тестов
| v1 finding | Severity | Статус | Что сделано |
|---|---|---|---|
| F-1 — backend whitelist не пропускает `tri` | P1 | **RESOLVED** | `src/api/main.py:1252`: `("hypso", "hillshade") → ("hypso", "hillshade", "tri")` + docstring с обоснованием (nginx на prod/test перехватывает, но dev-режим должен поддерживать нативно) |
| F-2 — integration-тест не параметризован по layer | P2 | **RESOLVED** | `test_terrain_tile_available_z9_z10_z11` параметризован по `["hillshade", "tri"]` × `[9, 10, 11]`; добавлен явный `test_known_terrain_layer_accepted_by_whitelist[hypso/hillshade/tri]` |
| F-3 — комментарий в `HILLSHADE_PAINT` не упоминает MapLibre clamping ниже z9 | P3 | OPEN (косметика) | Не блокер; см. ниже |
| F-4 — `from __future__ import annotations` неиспользован | P3 | N/A | В текущем integration-тесте `from __future__` отсутствует; в unit-тесте остался, но это микро-косметика |
- Unit (Вариант B по REQ-F-13) — статический парсинг `app.js`/`index.html`:
значения и монотонность stops, отсутствие старого порога `< 10`,
обратная совместимость, hint-текст, число вызовов. Локальный прогон
**17/17 PASS**.
- Integration — параметризация по обоим слоям, whitelist-регрессия
(`test_known_terrain_layer_accepted_by_whitelist`), cache-header;
404-проверки не зависят от наличия PNG, тайловые тесты корректно
`skipif` при отсутствии z9-данных.
- Примечание по среде: в песочнице ревью модуль
`tests/integration/...` не импортируется из-за отсутствия `shapely`,
но `shapely==2.0.4` указан в `pyproject.toml` → в CI импорт проходит.
Это дефект локального окружения, не кода (подтверждено
`13-test-report.md`: полный регресс 254 passed).
Все P0/P1 v1 закрыты.
## 6. Findings
## Тесты
| ID | Severity | Описание |
|---|---|---|
| F-INFO-1 | P3 (informational) | `src/api/main.py:1252` добавляет `tri` в whitelist слоёв (`hypso`/`hillshade`/`tri`). Формально ТЗ §2 / REQ-F-18 и ADR-017 «Классификация изменения» декларировали «main.py без изменений», но это **необходимый и ранее завизированный (F-1) фикс**: фронтенд запрашивает `/terrain/tri/{z}/{x}/{y}.png`, и без whitelist слой «Перепады» возвращал бы 404 «Unknown layer» в dev-режиме (без nginx). Изменение обратно-совместимо — добавление допустимого значения, без новых query/headers/кодов; контракт endpoint'а не ломается. Покрыто регрессией `test_known_terrain_layer_accepted_by_whitelist` + парным `test_unknown_terrain_layer_returns_404`. Не блокер. |
- **Unit (`tests/unit/test_terrain_paint.py`).** 17 тестов, **17 PASS**
локально (Python 3.12.13, pytest 8.3.3, время 0.04s). Покрывают:
объявление констант, форму `interpolate`-выражений, ключевые stops
(z9/11/14 для hillshade, z8/10/11 для TRI), монотонность,
`nearest`-resampling, регрессию порога `< 9` и текста «Зум 9+»,
обратную совместимость `applyTerrainLayer`, корректное использование
констант в вызовах.
Findings уровня P0/P1/P2 нет.
- **Integration (`tests/integration/test_terrain_z9_tiles.py`).**
13 тестов: **6 passed, 7 skipped** в sandbox.
- Skipped: тесты, требующие реальных PNG-тайлов
(`test_terrain_tile_available_z9_z10_z11[*]`,
`test_terrain_tile_cache_control_immutable`) — корректное поведение
через `_maybe_skip`.
- Passed: whitelist-регрессия для всех трёх слоёв
(`hypso/hillshade/tri`), 404 на `unknown_layer`, 404 на
missing tile, 404 на невалидный zoom. Эти тесты доказывают,
что фикс F-1 работает (для `tri` теперь возвращается
`"Tile not found"`, а не `"Unknown layer"`).
## 7. Примечание по статусу тестирования
## Качество кода
`13-test-report.md` имеет `verdict: BLOCKED`. Блокировка относится к
**данным деплой-стадии** (на test-среде не нарезаны z9-тайлы hillshade →
pre-deploy gate AC-19 и визуальная приёмка z9 не проходят), а **не к
коду**. Разблокировка = PH-6 follow-up (догенерить z9-тайлы), вне
четырёх осей code-review. По коду, ТЗ, ADR и автотестам блокеров нет.
- Стиль соответствует существующему `app.js` (vanilla JS, JSDoc,
комментарии-маркеры `// ET-NNN:`).
- Изменение функции `applyTerrainLayer` минимально-инвазивное:
новая нормализация в 4 строки + переменная `paint`, остальное —
переименование параметра. Никаких ломок других call-sites
(их всего 2, оба в `onTerrainCheckbox`).
- Backend-фикс whitelist'а — 1 строка кода + docstring; не меняет
сигнатуру endpoint'а и не вводит новых query/headers/code-path'ов
(REQ-F-18 формально сохранён).
- Все новые константы (`HILLSHADE_PAINT`, `TRI_PAINT`) UPPER_SNAKE_CASE,
как принято в `app.js`.
- Комментарии содержат ссылки на ADR-017, RTM-аргументы по stops,
ссылку на review F-1 в backend-docstring.
- Нет дублирования, нет dead code, нет `console.log`, нет
закомментированного старого кода.
## 8. Вердикт
## Findings (текущая ревизия)
### P3 — Комментарий в `HILLSHADE_PAINT` не упоминает MapLibre clamping ниже z9
**Где.** `src/web/app.js:2728-2733`.
**Замечание.** Stops opacity начинаются с `9, 0.65` — MapLibre сделает
clamping на нижнем стопе, поэтому при z<9 (если когда-нибудь UI-gate
уберут) opacity всё равно будет 0.65, что попадёт в render.
В текущем scope не проблема (UI-gate отрубает чекбокс при z<9), но
если в будущем порог понизят — нужно будет добавить нижний stop
`8, 0.00`.
**Действие.** Опционально. **Не блокер.**
### P3 — `from __future__ import annotations` в unit-тесте
**Где.** `tests/unit/test_terrain_paint.py:15`.
**Замечание.** Не используется (нет forward-ref в аннотациях). Не вредит.
**Действие.** Опционально. **Не блокер.**
## Вердикт
Реализация полностью соответствует ТЗ и ADR-017; код и тесты
качественны; unit-тесты зелёные. Единственное расхождение с буквой ТЗ
(whitelist `tri` в main.py) — обоснованный, задокументированный и ранее
завизированный фикс уровня P3. P0/P1 отсутствуют.
**APPROVED.**
- P0/P1 не найдено.
- P1 из review v1 (backend whitelist) и P2 (integration coverage) —
закрыты.
- Оставшиеся два P3 — косметика, не влияют на функциональность.
Реализация ET-013 точно соответствует TRZ REQ-F-01..F-21 и ADR-017.
Тестовое покрытие достаточное:
- AC-01/02/04/05/15/17/22 — закрыты unit-тестами (зелёные).
- AC-16 — закрыт integration-тестами (структурно корректно, skip без данных, whitelist-регрессия зелёная).
- Поведенческие AC (AC-03, AC-06..AC-13, AC-19, AC-21) — корректно
переданы Тестеру для исполнения в test-среде.
## Сводная таблица findings
| ID | Severity | Где | Кратко | Действие |
|---|---|---|---|---|
| F-3 | P3 | `src/web/app.js:2728-2733` | комментарий не учитывает MapLibre clamping ниже z9 | опционально добавить явный stop `8, 0.00` |
| F-5 | P3 | `tests/unit/test_terrain_paint.py:15` | `from __future__ import annotations` неиспользован | косметика |
P0/P1 отсутствуют → **APPROVED**.

File diff suppressed because it is too large Load Diff