# LDD baseline: 2026-10-27/28 Первый и второй LDD-циклы проверки текущей функциональности LMS. Добавлены реестр claims, gate `evidenceCheck`, runtime/migration/mutation скрипты и браузерный E2E на Playwright. В ходе проверки найден и исправлен реальный дефект Jackson 3. ## 1. Что проверялось Реестр: `docs/evidence/claims.json`, **37 утверждений**. | Критичность | Claims | Proven | Gaps | |---|---:|---:|---:| | P0 | 20 | 20 | 0 | | P1 | 17 | 17 | 0 | | **Итого** | **37** | **37** | **0** | Домены: - доступы: аноним/студент/преподаватель/админ, чужие курс/лаба/студент/группа, внутренние API identity; - повышение: dry-run, apply, идемпотентность, rollback, cancel; - жизненный цикл: академ, возврат, отчисление, архив, восстановление, вход; - профиль студента и скачивание сдач; - материалы и активы; - миграция V13 и полный upgrade с master-схемы; - аудит: токен, admin-only, сохранность после удаления, representative-хуки; - группы курса, авторство материалов, ведомость, UI/контракты, импорт, копирование лабораторных; - runtime-smoke, mutation testing, браузерный E2E. ## 2. Команды и результаты ### 2.1. Автоматические тесты ```bash ./gradlew test --rerun-tasks ``` Результат: **276 тестов, 0 failures, 0 errors, 0 skipped**. `ktlintCheck` и `detekt` — зелёные. ### 2.2. LDD gate ```bash ./gradlew evidenceCheck ``` Результат: **37/37 claims proven, P0 gaps = 0**. Отчёт: `build/reports/evidence/index.md`. Gate устроен так: - каждый claim ссылается на конкретный JUnit-тест `Class#method`; - P0 без зелёного теста валит сборку; - P1-пробел показывается в отчёте; - runtime-проверки читаются из `build/evidence/*.json` и тоже должны быть `passed`, если claim на них ссылается. ### 2.3. Upgrade с master-схемы ```bash ./scripts/ldd-migration-upgrade.sh ``` Сценарий: одноразовая PostgreSQL 18, master identity `V1–V3`, academic `V1–V5`, progress `V1–V9,V11,V12`, синтетические данные, затем ветка: identity `V4–V10`, academic `V6–V12`, progress `V13`. Проверено: - `identity.audit_events` создана; - `students`, `groups`, `membership_history` сохранились; - `labs.course_id`, `chapters.course_id`, `article_assets` созданы; - `grade_comments.author_account_id`, `lab_grades.updated_by_account_id` созданы; - оценки и комментарии сохранились; - повторное применение `V13` идемпотентно. Результат: **PASS**, evidence: `build/evidence/migration.json`. ### 2.4. Runtime-smoke полного стека ```bash ./scripts/ldd-runtime.sh ``` Сценарий: одноразовая БД, `bootJar`, запуск identity/academic/progress/gateway/web, реальные HTTP-вызовы через gateway. Проверено: - health всех пяти сервисов = `UP`; - `adminExists=false` до setup, создание админа, `/auth/me` = `ADMIN`; - создание группы, курса, преподавателя, привязка группы, создание лабы; - преподаватель входит и видит свой курс, лабу и состав группы; - чужой преподаватель получает `403` на курс, лабу и аудит; - админ видит audit-события `COURSE_CREATE`, `TEACHER_CREATE`, `COURSE_TEACHER_ASSIGN`, `COURSE_GROUP_ATTACH`, `LAB_CREATE`; - web `/login` отдаёт `200`, публичное дерево материалов доступно, курсовые материалы анонимно — `401`. Результат: **PASS**, evidence: `build/evidence/runtime.json`. ### 2.5. Mutation testing ```bash ./scripts/ldd-mutation.sh ``` PIT запускается через CLI с JUnit 4 harness: JUnit5-плагин PIT несовместим с JUnit Platform 6 из Spring Boot 4. | Компонент | Мутаций | Убито | Test strength | Порог | |---|---:|---:|---:|---:| | `CourseAccessService` | 56 | 42 | **75%** | 70% | | `PromotionPlanner` | 162 | 109 | **69%** | 60% | Результат: **PASS**, evidence: `build/evidence/mutation.json`. Остаток — эквивалентные мутации, Kotlin-интринсики и ветки, не входящие в текущий P0-контур. ### 2.6. Браузерный E2E ```bash ./scripts/ldd-browser.sh ``` Playwright/Chromium на полном стеке, одноразовая БД: - admin: вход, `/admin/courses` с курсом, `/admin/audit` с событием; - teacher: вход, курс, ведомость (группа/студент, без админских кнопок), профиль студента, создание главы курса; - anonymous: `/admin/audit` → `/login`; - student: вход, `/admin/audit` → `/student`, `/learn/course/{no}`. Результат: **4/4 passed**, evidence: `build/evidence/browser.json`. Дополнительно проверены сдача файла студентом и mobile-размер teacher-страницы. ### 2.7. Конкурентные apply/rollback Добавлен `PromotionConcurrencyIntegrationTest` (без `@Transactional`, два потока, advisory lock): два одновременных apply идемпотентны и пишут history один раз; два одновременных rollback дают ровно один успех и один `ConflictException`, состояние восстанавливается один раз. ### 2.8. Нагрузочный smoke `ldd-runtime.sh` выполняет 100 чтений (10 workers) курса, лаб, профиля и аудита: **0 ошибок, avg 0.141 c, p95 0.868 c** (порог p95 < 2 c). ### 2.9. Release gate `./scripts/ldd-release.sh` последовательно запускает тесты/линтеры, upgrade, mutation, runtime и browser E2E, затем финальный `evidenceCheck`. В `.gitlab-ci.yml` добавлен ручной job `release-evidence` с Chromium/Node. ### 2.10. Найденный дефект Первый browser E2E упал на создании студента: API вернул `400`, потому что Jackson 3 не применял Kotlin-модуль, и DTO с default-значениями требовали все поля JSON. Исправлено: `jackson-module-kotlin` для Jackson 3 + `JsonMapperBuilderCustomizer` в identity/academic/progress/web. Добавлен регрессионный тест `TeacherIntegrationTest.student creation accepts omitted optional json fields`. ## 3. Что это доказывает - Критичные P0-инварианты доступа, повышения, жизненного цикла, профиля, материалов, миграции и аудита имеют зелёные автоматические свидетельства. - Приложение собирается, мигрирует с master-схемы и поднимается полным стеком на чистой БД. - Ключевой доменный поток «админ → группа → курс → преподаватель → лаба» проходит через реальные HTTP/gateway/БД и браузер. - Чужой преподаватель не получает доступ к курсу/лабе/аудиту на реальном стеке. - Аудит пишется и читается; upgrade не теряет синтетические данные. - Мутационная прочность критичных компонентов измерена, а не заявлена. - Реальный дефект DTO/Jackson найден именно E2E-контуром и закрыт тестом. ## 4. Чего это не доказывает 1. **Mutation testing не 100%.** Остаются эквивалентные мутанты и Kotlin/Spring-специфичные мутации; PIT harness — JUnit 4, а не JUnit 5. 2. **Property-based тесты покрывают не все ветки.** Есть генераторы для матрицы доступа, планировщика и 10 транзакционных apply/rollback-кейсов, но не для всех сочетаний полей и распределённой нагрузки. 3. **Браузерный E2E — один Chromium и 4 сценария.** Нет визуальной регрессии, Safari/Firefox и полного мобильного набора страниц. 4. **Нагрузочный smoke — не benchmark.** Одна машина, синтетические данные, без SLA production. 5. **Legacy-активы без `article_assets` остаются публичными.** 6. **JWT живёт до 30 дней.** Web перепроверяет статус, прямой API — нет. 7. **Ведущие нули номера группы нормализуются** (`01` → `1`). 8. **Нет пагинации/keyset** для части списков и N+1 в отдельных экранах. 9. **Runtime/mutation/browser E2E не входят в unit-CI**; это release-скрипты. ## 5. Вывод Текущая функциональность прошла LDD-контур: **37/37 claims proven, P0 gaps = 0**, 273 теста, upgrade, mutation baseline и браузерный E2E зелёные. Это достаточное основание продолжать доработки, но не «формальное доказательство всей системы». Следующий цикл LDD: 1. расширить browser E2E на публикацию оценки и остальные мобильные страницы; 2. добавить нагрузочный профиль с реалистичным объёмом групп/студентов; 3. закрыть известные продуктовые риски: legacy-активы, JWT 30 дней, ведущие нули, пагинация/N+1; 4. сделать release-evidence job обязательным для тегов.