Files
LMS/docs/evidence/baseline-2026-10-27.md

210 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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 обязательным для тегов.