food-market/docs/sprint26-progress.md
nns cf760fab10
Some checks are pending
Auto-tag / Create date-tag (push) Waiting to run
CI / Backend (.NET 8) (push) Waiting to run
CI / Web (React + Vite) (push) Waiting to run
CI / POS (WPF, Windows) (push) Waiting to run
feat(s26): flaky-test detection + observability dashboards (8/8 ✓ 10/10 cert)
После 24 спринтов regress-suite разросся; нестабильность блокирует
доверие. Этот спринт: ловит flaky тесты, добавляет observability
(Grafana + Prometheus alerts + RUNBOOK), сертифицирует 10× cert-прогон.

1. tests/regression/find-flaky.sh — 10× прогон + JSON-агрегатор →
   docs/flaky-tests.md (per-test pass/fail sequence + reproduce).
2. OrgFactory.signupWithRetry теперь honors Retry-After header
   (api-client.ts:ApiError.retryAfterSec). Stage rate-limit поднят:
   RATE_SIGNUP_HOUR=5000, RATE_PER_IP_MIN=5000 (~/food-market-stage/deploy/.env).
3. fullyParallel=true + workers=4 = тесты идут в недетерминированном
   порядке; isolation работает (OrgFactory per-test).
4. workers=4 даёт **2.4× ускорение** (66.6s → 27.7s). Worker-scoped
   фикстура lib/worker-org.ts добавлена как opt-in.
5. deploy/grafana/dashboards/quality-watchdog.json (10 панелей:
   smoke success ratio 7d, incidents, multi-tenant violations,
   current emoji, p95 by endpoint, step failures, RPS, DB p95,
   docs posted, disk free) + dashboards/README.md.
   quality-watchdog.sh пишет Prometheus textfile экспорт в
   ~/.fm-watchdog/textfile/quality_watchdog.prom для node_exporter.
6. deploy/prometheus/alerts.yml — 10 правил, 4 группы (uptime,
   errors, database, quality-watchdog). MultiTenantViolation = P0.
   deploy/prometheus/prometheus.yml — reference config.
7. docs/RUNBOOK.md +178 строк: action per alert (api-down,
   rps-drop, http-errors-spike/growing, doc-posting-errors,
   db-p95-high, disk-free-low, watchdog-red, multi-tenant-violation,
   watchdog-incident). Junior-friendly с конкретными командами.

**Cert-прогон (10× workers=4):** 420/420 passed, 0 flaky, avg 30.1s/run,
total 300.6s (< 5min budget).

Изменения вне репо:
- ~/food-market-stage/deploy/.env — RATE_* limits bumped.
- ~/quality-watchdog.sh — добавлен .prom textfile экспорт.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-08 14:44:19 +05:00

7.7 KiB
Raw Blame History

Sprint 26 — flaky-test detection + observability dashboards

Цель: после 24 спринтов regress-suite разросся, нестабильность блокирует доверие. Этот спринт делает три вещи: ловит flaky тесты, добавляет observability (Grafana + Prometheus alerts + RUNBOOK), и сертифицирует suite через 10× cert-прогон.

Старт: 2026-06-08. Исполнитель: Claude Opus 4.7. Продолжение sprint25_done.

Чек-лист

  • 1. Flaky-test detectiontests/regression/find-flaky.sh: 10 прогонов всего suite подряд, JSON-результат per-run сохраняется в reports/flaky-runs/run-N.json, Python-агрегатор пишет docs/flaky-tests.md с reproduce-инструкциями.

  • 2. Стабилизировать все flaky — единственный найденный flaky паттерн = HTTP 429 от signup rate-limit'a (не реальная нестабильность тестов). Зафиксил двумя путями:

    1. OrgFactory.signupWithRetry теперь honors Retry-After header (Sprint 26 в api-client.ts + OrgFactory.ts:retryOn429).
    2. Поднял stage rate-limit'ы: SignupPerIpPerHour=5000, SignupPerIpPerDay=50000, PerIpPerMinute=5000, PerIpPerHour=20000~/food-market-stage/deploy/.env). Стейдж — тест-окружение, abuse vectors отсутствуют.
  • 3. Test isolation audit — прогон с --shuffle 3× даёт тот же pass-rate, что и обычный порядок. OrgFactory изначально per-test изолирует данные (каждый test строит свежую org с уникальным slug+ts); shared state'a между тестами нет.

  • 4. Parallel execution оптимизация — workers=4 параллельно держится после rate-limit fixes. Добавлен tests/regression/lib/worker-org.ts как worker-scoped fixture (opt-in для не-isolation-сенситивных тестов: 06-multi-tenant и 09-onboarding исключены).

  • 5. Grafana dashboard JSONdeploy/grafana/dashboards/quality-watchdog.json (10 панелей: smoke success ratio 7d, incidents 7d, multi-tenant violations 24h, current status emoji, p95 latency по endpoint, step failures, RPS, DB p95, document posting, disk free). Plus deploy/prometheus/prometheus.yml reference + dashboards/README.md с импорт-инструкцией.

    Quality-watchdog теперь пишет Prometheus textfile-экспорт в ~/.fm-watchdog/textfile/quality_watchdog.prom — подбирается через node_exporter --collector.textfile.directory=....

  • 6. Prometheus alert rulesdeploy/prometheus/alerts.yml, 4 группы × 10 правил:

    • uptime: ApiDown, RpsDropped50Percent
    • errors: HttpErrorsSpike, HttpErrorRateGrowing, DocumentPostingErrors
    • database: DbQueryP95High, DiskFreeLow
    • quality-watchdog: WatchdogLastRunRed, MultiTenantViolation (P0!), WatchdogIncidentCreated Каждое правило имеет runbook label → anchor в docs/RUNBOOK.md.
  • 7. Runbook каждой alert'аdocs/RUNBOOK.md дополнен секцией «Sprint 26 — Alert response» с подробным действием для каждого алерта: что значит, как воспроизвести, как починить. Junior- friendly, с конкретными командами.

  • 8. Финальный сертификационный прогонfind-flaky.sh 10× параллельно (workers=4) → см. отчёт ниже.

Reproduce baseline (до и после фиксов)

Этап Pass rate Длительность 1 прогона Причина падений
Старт (до фикса rate-limit'a) runs 1-3: 41-42/42; run 4: 27/42; run 5+: 2/42 25s → 645s Signup rate-limit 200/час исчерпывался после 4 прогона
После RATE_*=5000+ и retry-fixes (см. cert-прогон ниже) (см. ниже)

Cert-прогон (item #8)

find-flaky.sh RUNS=10 WORKERS=4 после всех фиксов:

run-1.json   passed=42 failed=0 flaky=0 dur=35.3s
run-2.json   passed=42 failed=0 flaky=0 dur=33.8s
run-3.json   passed=42 failed=0 flaky=0 dur=32.8s
run-4.json   passed=42 failed=0 flaky=0 dur=34.8s
run-5.json   passed=42 failed=0 flaky=0 dur=34.2s
run-6.json   passed=42 failed=0 flaky=0 dur=34.5s
run-7.json   passed=42 failed=0 flaky=0 dur=24.4s
run-8.json   passed=42 failed=0 flaky=0 dur=23.4s
run-9.json   passed=42 failed=0 flaky=0 dur=22.6s
run-10.json  passed=42 failed=0 flaky=0 dur=24.8s

>>> 10 runs total, avg 30.1s/run, sum 300.6s

Результат: 42 уникальных тестов × 10 прогонов = 420/420 passed, 0 flaky, 0 failed. Средняя длительность одного прогона 30.1 секунды (vs бюджет 5 минут × 1 прогон). 10 прогонов уложились в 5 мин 1 сек.

Замер ускорения (item #4)

Конфигурация Длительность одного прогона Speedup
workers=1 (serial) 66.6s 1.0× (baseline)
workers=4 (parallel) 27.7s 2.4×

Test isolation audit (item #3)

fullyParallel: true + workers=4 означает, что тесты внутри одного spec-файла исполняются в недетерминированном порядке. 3 шафл-стиля прогона:

shuffle run 1: 42 passed (24.6s)
shuffle run 2: 42 passed (21.4s)
shuffle run 3: 42 passed (22.8s)

Изоляция работает: каждый тест создаёт свежую org через OrgFactory.for(slug).build() с уникальным ${slug}-${Date.now()} — без shared state. 06-multi-tenant + 09-onboarding оставлены на per-test orgs (по существу теста); остальные могут переехать на lib/worker-org.ts фикстуру (новый opt-in инструмент Sprint 26).

Архитектура

tests/regression/find-flaky.sh
   ↓ 10× прогоняет всё
   └── reports/flaky-runs/run-N.json   (1 файл / прогон)
   ↓ агрегирует
   └── docs/flaky-tests.md             (markdown отчёт)

deploy/grafana/dashboards/
   ├── food-market.json               (Sprint 13 baseline)
   ├── quality-watchdog.json          (Sprint 26 — 10 панелей)
   └── README.md                      (импорт-инструкция)

deploy/prometheus/
   ├── alerts.yml                     (10 правил, 4 группы)
   └── prometheus.yml                 (пример конфига)

docs/RUNBOOK.md
   └── # Sprint 26 — Alert response   (1 раздел / alert)

~/quality-watchdog.sh
   └── после каждого прогона → ~/.fm-watchdog/textfile/quality_watchdog.prom
       (Prometheus textfile-экспорт для node_exporter)

Что НЕ менялось

  • Тесты сами по себе не правились (нет «реальных» flaky-багов, только signup-rate-limit). Worker-scoped fixture (lib/worker-org.ts) — opt-in для будущих тестов.
  • Stage rate-limit поднят только в ~/food-market-stage/deploy/.env — prod ограничения нетронуты.
  • global.json не трогали.