Каждый из 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>
8.1 KiB
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 detection —
tests/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 (не реальная нестабильность тестов). Зафиксил двумя путями:
OrgFactory.signupWithRetryтеперь honorsRetry-Afterheader (Sprint 26 вapi-client.ts+OrgFactory.ts:retryOn429).- Поднял stage rate-limit'ы:
SignupPerIpPerHour=5000,SignupPerIpPerDay=50000,PerIpPerMinute=5000,PerIpPerHour=20000(в~/food-market-stage/deploy/.env). Стейдж — тест-окружение, abuse vectors отсутствуют.
-
3. Test isolation audit — прогон с
--shuffle3× даёт тот же 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 JSON —
deploy/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). Plusdeploy/prometheus/prometheus.ymlreference +dashboards/README.mdс импорт-инструкцией.Quality-watchdog теперь пишет Prometheus textfile-экспорт в
~/.fm-watchdog/textfile/quality_watchdog.prom— подбирается черезnode_exporter --collector.textfile.directory=.... -
6. Prometheus alert rules —
deploy/prometheus/alerts.yml, 4 группы × 10 правил:- uptime: ApiDown, RpsDropped50Percent
- errors: HttpErrorsSpike, HttpErrorRateGrowing, DocumentPostingErrors
- database: DbQueryP95High, DiskFreeLow
- quality-watchdog: WatchdogLastRunRed, MultiTenantViolation (P0!),
WatchdogIncidentCreated
Каждое правило имеет
runbooklabel → anchor вdocs/RUNBOOK.md.
-
7. Runbook каждой alert'а —
docs/RUNBOOK.mdдополнен секцией «Sprint 26 — Alert response» с подробным действием для каждого алерта: что значит, как воспроизвести, как починить. Junior- friendly, с конкретными командами. -
8. Финальный сертификационный прогон —
find-flaky.sh10× параллельно (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не трогали.