From a8c01f01e9d6b01c8c5ac18fe496bbbb1f506773 Mon Sep 17 00:00:00 2001 From: IK Date: Mon, 21 Sep 2026 07:55:09 +0700 Subject: [PATCH] test: enforce first-answer evidence contract --- apps/web/tests/task-journey.spec.ts | 6 +++++ docs/ROADMAP.md | 4 +-- docs/ux-task-review-2026-09-21.md | 38 +++++++++++++++++++++++++++++ 3 files changed, 46 insertions(+), 2 deletions(-) create mode 100644 docs/ux-task-review-2026-09-21.md diff --git a/apps/web/tests/task-journey.spec.ts b/apps/web/tests/task-journey.spec.ts index e40c1b1..02466fa 100644 --- a/apps/web/tests/task-journey.spec.ts +++ b/apps/web/tests/task-journey.spec.ts @@ -8,11 +8,17 @@ test("player can complete the first useful answer journey", async ({ page }) => const firstCard = page.locator(".spot-card").first(); await expect(firstCard).toBeVisible(); + await expect(firstCard).toContainText("Свежесть"); + await expect(firstCard).toContainText("Наблюдения"); + await expect(firstCard).toContainText("Координаты"); + await expect(firstCard.locator(".source-chip").first()).toBeVisible(); await expect(firstCard.getByText("Открыть точку")).toBeVisible(); await firstCard.getByText("Открыть точку").click(); await expect(page.getByRole("heading", { name: /^Точка / })).toBeVisible(); await expect(page.getByRole("heading", { name: "Что взять" })).toBeVisible(); + await expect(page.locator("aside .data-passport")).toContainText("Доверие"); + await expect(page.locator("aside .data-passport")).toContainText("Наблюдения"); const save = page.getByRole("button", { name: "Сохранить в план" }); await save.click(); await expect(page.getByRole("button", { name: "В плане" })).toHaveAttribute("aria-pressed", "true"); diff --git a/docs/ROADMAP.md b/docs/ROADMAP.md index c827b68..98c84e2 100644 --- a/docs/ROADMAP.md +++ b/docs/ROADMAP.md @@ -92,12 +92,12 @@ Результаты сравнительного аудита и ссылки сохранены в [ux-competitive-audit.md](ux-competitive-audit.md). Целевой критерий проекта: RF4 Spotter должен быстрее и честнее отвечать на вопрос «куда идти, на что ловить и почему этому можно доверять», чем каталог или лента community-постов. -- [ ] **U01 · UX-контракт и scorecard.** Контракт маршрутов, смысловой порядок ответа, словарь статусов и целевые метрики зафиксированы в [ux-contract.md](ux-contract.md); для home, spot, waterbody, plan и tackle описаны первый ответ и обязательное объяснение. Сквозной Playwright task journey проверяет home → spot → «Что взять» → plan и возврат query-контекста. Осталось провести ручной task-based review и собрать completion rate на пилоте. +- [ ] **U01 · UX-контракт и scorecard.** Контракт маршрутов, смысловой порядок ответа, словарь статусов и целевые метрики зафиксированы в [ux-contract.md](ux-contract.md); для home, spot, waterbody, plan и tackle описаны первый ответ и обязательное объяснение. Сквозной Playwright task journey проверяет home → spot → «Что взять» → plan и возврат query-контекста, включая source/evidence-поля первой карточки; ручной сценарий и критерии зафиксированы в [ux-task-review-2026-09-21.md](ux-task-review-2026-09-21.md). Осталось провести review с участниками и собрать completion rate на пилоте. - [ ] **U02 · Главный сценарий «рыба → водоём → точка → снасть».** Главная сохраняет рыбу, водоём, период и сортировку в shareable URL, явно показывает контекст запроса и даёт текстовый CTA «Открыть точку» на каждой карточке, включая mobile; первый экран ограничен пятью вариантами, а остальные доступны через сохраняющую query-контекст серверную пагинацию; empty-state предлагает вернуться к полному набору данных. Осталось добавить режим map. Acceptance: первый полезный вариант виден без регистрации, back/refresh сохраняют контекст, mobile не теряет фильтры. - [ ] **U03 · Evidence/trust card.** Общий evidence-контракт используется на activity-карточках, detail точки, водоёма и карточках снастей: freshness с текстовым `Свежо`/`Устарело`, явный период расчёта, completeness, confidence/статус, source badges и доступные доменные поля; при выборке меньше 3 явно показано отдельное состояние `Недостаточно данных`, ограниченный источник не смешивается с неполными полями, а явно переданные provenance-конфликты видны текстом. Targeted E2E и API-тест проверяют публичные пути, период, 48-часовой порог и конфликт источников. - [ ] **U04 · List/map и progressive disclosure.** List остаётся честным базовым режимом: фильтры, сортировка, URL-состояние и evidence-карточки уже работают без имитации координатной карты. Следующий шаг — единый list/map-контракт после подтверждения геометрии; на mobile карта должна открываться отдельным действием. Вторичные raw/provenance-поля не исчезают и раскрываются по запросу. - [ ] **U05 · Mobile-first и сохранённый план рыбалки.** `/plan` поддерживает список до 5 локальных вариантов, удаление, очистку, переход к точке, print/PDF и восстановление из shareable URL; кнопка «Поделиться планом» использует native share или clipboard fallback. Detail-кнопка сохраняет данные с `aria-pressed` и восстанавливается после reload. Print/mobile-контракт проверяет 320/390 px, лимит импорта и отсутствие горизонтального overflow; карточка плана теперь сравнивает подтверждённые метод/проводку и явно показывает риск по выборке/уверенности. -- [ ] **U06 · Контентная и визуальная иерархия.** Для detail точки действие «Что взять» выделено отдельным заголовком, provenance и качество собраны в общем паспорте данных, а подтверждённые метод/проводка видны рядом с последними уловами; статусы дополнительно передаются текстом, малая выборка не маркируется как готовая рекомендация, а дублирующие catches/players/confidence убраны из вторичной колонки activity-карточки. Mobile route-contract проверяет первый ответ и действие на home, spot, waterbody, plan и tackle; остаётся ручной review визуальных деталей. +- [ ] **U06 · Контентная и визуальная иерархия.** Для detail точки действие «Что взять» выделено отдельным заголовком, provenance и качество собраны в общем паспорте данных, а подтверждённые метод/проводка видны рядом с последними уловами; статусы дополнительно передаются текстом, малая выборка не маркируется как готовая рекомендация, а дублирующие catches/players/confidence убраны из вторичной колонки activity-карточки. Mobile route-contract проверяет первый ответ и действие на home, spot, waterbody, plan и tackle, а task regression требует source/evidence-поля; остаётся ручной review визуальных деталей по [ux-task-review-2026-09-21.md](ux-task-review-2026-09-21.md). - [ ] **U07 · UX-приёмка и измерения.** Playwright-контракты уже покрывают query journey, сквозной task journey, evidence states, saved plan, share/print, accessibility и visual matrix; unit-контракт добавил детерминированные stale- и blocked-подписи, а insufficient-data теперь отделён от incomplete в публичном паспорте. `/status` явно сообщает, что при ограничении источника опубликованные данные сохранены. Visual-matrix regression теперь проверяет `192` комбинации, включая spot detail и plan; representative review зафиксирован в `docs/ux-reference-review-2026-09-21.md`. Остаётся получить production Lighthouse/CLS/INP/time-to-first-useful-answer после пилота и принять решение о долговременном хранении screenshots. - [ ] **Q01 · Документы источников — реестр готов, нужны первичные подтверждения.** Создан единый production-gate с атрибуцией, общим лимитом 30 минут, хранением и процедурой отзыва для RF4DB, RF4-STAT, RF4MAP, RF4 Posts и официального RF4. До открытой публикации приложить устойчивые ссылки/копии первичных разрешений, контакты, даты и отдельно подтвердить право на изображения; пустое поле блокирует соответствующий источник. diff --git a/docs/ux-task-review-2026-09-21.md b/docs/ux-task-review-2026-09-21.md new file mode 100644 index 0000000..31adc3d --- /dev/null +++ b/docs/ux-task-review-2026-09-21.md @@ -0,0 +1,38 @@ +# Task-based UX review — 2026-09-21 + +## Сценарий альфы + +Проверяем, может ли новый игрок без подсказки пройти путь: + +`главная → первая точка → что взять → сохранить → мой план`. + +Ручной прогон выполняется на mobile `390 × 844` в чистом профиле браузера: + +1. Открыть `/` и выбрать первую видимую карточку горячей точки. +2. Проверить, что до перехода видны координаты, freshness, sample size, + источник и текстовая причина доверия. +3. Открыть «Открыть точку» и найти координатный блок, activity/evidence и + заголовок «Что взять». +4. Сохранить точку в план, вернуться назад и убедиться, что query-контекст + сохранился. +5. Открыть `/plan`, проверить одну сохранённую точку, метод/проводку и риск, + затем проверить удаление и восстановление empty-state. + +## Текущий результат + +Автоматический task journey проходит этот путь и теперь дополнительно требует +на первой карточке `Свежесть`, `Наблюдения`, `Координаты` и source badge, а на +detail — `Доверие` и `Наблюдения` в паспорте данных. Мобильный route-contract +также проверяет первый ответ и действие на home, spot, waterbody, plan и tackle. + +Это regression evidence, а не измерение поведения реальных участников. +Completion rate `≥ 80%` и time-to-first-useful-answer нужно собрать на пилоте +по этому сценарию, минимум с записью отказов и причины остановки. + +## Acceptance notes + +- не считать «точка открылась» успешным завершением без evidence и действия; +- не считать слабую выборку рекомендацией без явного состояния + «Недостаточно данных»; +- фиксировать отдельно desktop и mobile, а также чистый и повторный визит; +- production Lighthouse/INP и серверные p95 не заменяются этим review.