food-market/docs/sprint26-progress.md
nns e30861fb57
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(s27): cross-feature integration + soak + crash recovery (8/8 ✓)
Каждый из 26 спринтов работал в изоляции; этот спринт проверяет
взаимодействие — реально ли все фичи совместимы.

1. tests/integration/03-loyalty-signalr-i18n: программа PointsAccrual →
   карта → продажа 100₸ → начисление 10 баллов; SignalR через
   /hubs/notifications + WS получает SalePosted; ru-RU и en-US оба 200.
2. tests/integration/01-permissions-bulk-audit: manager без
   ProductsDelete/Edit → DELETE и bulk-archive оба 403 (атомарно);
   orgB не видит userId orgA в audit-log; orgB не видит товары orgA.
3. tests/integration/04-2fa-sso-permissions: providers endpoint OK;
   challenge Google без конфига → 503 с подсказкой; 2FA enroll+verify+
   disable работают с otplib TOTP; permissions для manager'a
   проверяются после 2FA enable.
4. tests/integration/02-ofd-mock-reports: PUT /api/organization/fiscal
   {provider:1} → Mock; 50 продаж имеют fiscalNumber.startsWith("MOCK-");
   sales report ≥50 транзакций; ABC классифицирует как A с share>0.5.
5. tests/integration/05-real-business-day: open→supply 100×2→50 sales→
   customer return→inventory→transfer→loss→demand→3 reports + stock
   invariant validated. Прогон 24.7s.
6. tests/load/soak-4h.js + monitor-soak.sh — k6 constant-arrival-rate
   50 RPS. Soak-lite 16m34s @ 20 RPS: 19863 iterations, 0 failures,
   p95 me=16.9ms / products=29.5ms / stats=стабильно, mem 320-344 MiB
   без линейного роста, PG conn 18, disk не двинулся. Без утечек.
7. tests/integration/06-edge-cases: 100 concurrent SignalR подключений
   = 100/100 успешных WS handshake; 90 параллельных запросов = 100%
   200, <8s, 0 5xx. Hangfire workers=2 не блокирует API.
8. Crash recovery test: host SIGKILL dotnet процесса → unless-stopped
   policy → recovery 11.7s ≤ 30s SLA. Найдено: docker kill (через CLI)
   = explicit-stop по политике Docker, не триггерит auto-restart;
   реальный host-side crash работает корректно.

Cert-прогон: 7 integration specs все зелёные за 1.2 мин.
0 production bugs found.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-09 03:09:17 +05:00

8.1 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×

Sprint 27 — продолжение

После Sprint 26 (stabilization + observability) — Sprint 27 проверил cross-feature integration на 6 темах + 4h-soak (lite-run 16m34s, 0 failures, p95 16-30ms) + crash recovery (11.7s < 30s SLA). 7 integration specs зелёные за 1.2 мин. Серьёзных багов не найдено. Подробности: docs/sprint27-progress.md.

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 не трогали.