# LDD: доказательное тестирование Этот каталог — реестр утверждений о системе и свидетельств того, что они выполняются. LDD здесь означает не «тесты вместо требований», а **риск-ориентированную проверку**: требование → проверяемое утверждение → независимый оракул → воспроизводимое свидетельство → допуск. ## Уровни - **P0** — утверждение о безопасности, сохранности данных, доступах или ключевом доменном правиле. P0 без зелёного свидетельства валит `./gradlew evidenceCheck`. - **P1** — важное поведение/UX/контракт. Пробел показывается в отчёте, но не блокирует сборку. - **runtime** — проверка на реально поднятом стеке. Быстрый smoke (`scripts/ldd-smoke.sh`) выполняется в CI на каждом push/MR; полный runtime/scale — в `release-evidence` и обязателен перед релизом. ## Реестр `claims.json` содержит: - `id` — стабильный идентификатор (`LDD-ACCESS-001`); - `title` — короткая формулировка; - `criticality` — `P0`/`P1`; - `status` — `active` или `gap`; - `requirement` — ссылка на ТЗ/отчёт; - `claim` — проверяемое утверждение (что именно истинно); - `oracle` — как это проверяется; - `evidence` — список `fully.qualified.Class#test name()` из JUnit XML; - `runtime` — идентификаторы проверок из `build/evidence/runtime.json`; - `limitations` — что утверждение **не** покрывает. ## Запуск ```bash # 1. Все тесты и линтеры ./gradlew test ktlintCheck detekt # 2. Гейт свидетельств (P0 без evidence = fail) ./gradlew evidenceCheck # 3. Быстрый smoke полного стека (то же, что CI job smoke) ./scripts/ldd-smoke.sh # 4. Полный runtime-smoke + scale load на одноразовой БД ./scripts/ldd-runtime.sh # 5. Проверка upgrade с master-схемы ./scripts/ldd-migration-upgrade.sh # 6. Mutation testing критичных P0-компонентов ./scripts/ldd-mutation.sh # 7. Браузерный E2E (Playwright: Chromium/Firefox/WebKit) ./scripts/ldd-browser.sh # 8. Полный release gate ./scripts/ldd-release.sh ``` Для E2E один раз установите зависимости и браузеры: `cd e2e && npm install && npx playwright install chromium firefox webkit`. Mutation harness использует JUnit 4: JUnit5-плагин PIT несовместим с JUnit Platform 6 из Spring Boot 4. Отчёт: `build/reports/evidence/index.md`. ## Правила 1. Новое P0-требование без свидетельства не мержится. 2. Свидетельство должно быть воспроизводимым в CI, а не «проверил руками». 3. Тест должен падать при поломке соответствующей логики. Для критичных пакетов это измеряется mutation testing: сейчас `CourseAccessService` — 75% test strength, `PromotionPlanner` — 69%. 4. Один тест может подтверждать несколько claims, но claim не должен опираться на тест, который проверяет только реализацию. 5. `limitations` обязателен: LDD не должен создавать иллюзию полного доказательства. 6. При переименовании теста обновляется `claims.json`; устаревшая ссылка — это gap, а не «забыли». 7. Runtime-свидетельства обязательны перед релизом; CI на каждом push/MR выполняет unit/integration-слой и быстрый smoke, полный release gate — для тегов (вручную для веток). ## Текущий baseline LDD-циклы выполнены 2026-10-27/28; последний — после закрытия продуктовых рисков: - **346 автоматических тестов**, 0 failures/errors; - **51 claims**: 25 P0 + 26 P1, **51/51 proven, P0 gaps = 0**. P0 — доступы, повышение, жизненный цикл, профиль/скачивание, материалы/активы (включая secure-by-default legacy-файлы), миграции V11–V13, аудит, refresh-токены и их отзыв; P1 — группы, авторство, UI, контракты, импорт, копирование лаб, keyset-пагинация, пакетные детали лабораторных, абсолютный потолок сессии, runtime, mutation и browser E2E; - mutation testing: `CourseAccessService` 75% test strength, `PromotionPlanner` 69%; - Playwright: 6 сценариев (admin, teacher, student/anonymous, сдача+mobile, cursor-аудит, инвентаризация активов) × Chromium/Firefox/WebKit = **18/18**, все зелёные; - масштабный load: 100 групп / 1000 студентов, 125 параллельных чтений, 0 ошибок, p95 < 1 с (порог p95 < 2 с); - CI: job `smoke` (`ldd-smoke.sh`) на каждом push/MR; полный `release-evidence` (`ldd-release.sh`) обязателен для тегов и ручной для веток. В ходе E2E найден и исправлен реальный дефект: Jackson 3 не применял Kotlin-модуль, поэтому DTO с default-значениями требовали все поля JSON (например, создание студента без `firstName`/`basis` давало 400). Остаточные ограничения: ручная инвентаризация legacy-активов на production, сдачи по выбранной лабораторной в ведомости, непроверенный первый CI-прогон на реальных runner'ах и отсутствие визуальной регрессии. Legacy-активы, срок access-токена, пагинация, N+1 деталей лабораторных, абсолютный лимит сессии и «ведущие нули» больше не являются открытыми рисками. Результаты — в `baseline-2026-10-27.md`.