docs: LDD baseline с mutation и browser E2E

This commit is contained in:
2026-10-28 00:02:06 +03:00
parent b7129b92e0
commit 238fd91f69
4 changed files with 120 additions and 49 deletions

View File

@@ -56,6 +56,8 @@ progress `:8083`, web `:8090`. Интерфейс: `http://localhost:8090`.
./gradlew ktlintFormat # автоформат Kotlin ./gradlew ktlintFormat # автоформат Kotlin
./scripts/ldd-runtime.sh # runtime-smoke полного стека на одноразовой БД ./scripts/ldd-runtime.sh # runtime-smoke полного стека на одноразовой БД
./scripts/ldd-migration-upgrade.sh # upgrade с master-схемы ./scripts/ldd-migration-upgrade.sh # upgrade с master-схемы
./scripts/ldd-mutation.sh # PIT: mutation strength критичных P0-компонентов
./scripts/ldd-browser.sh # Playwright E2E (нужен cd e2e && npm install)
``` ```
- `ktlint` отвечает за формат, `detekt` — за качество (сложность, вложенность, ошибки). - `ktlint` отвечает за формат, `detekt` — за качество (сложность, вложенность, ошибки).
@@ -65,8 +67,9 @@ progress `:8083`, web `:8090`. Интерфейс: `http://localhost:8090`.
не работает на JDK 25. не работает на JDK 25.
- Тестовая инфраструктура — `libs:test-support` (JUnit 5, MockK, Testcontainers `postgres:18`). - Тестовая инфраструктура — `libs:test-support` (JUnit 5, MockK, Testcontainers `postgres:18`).
- **LDD** — реестр проверяемых утверждений `docs/evidence/claims.json`; - **LDD** — реестр проверяемых утверждений `docs/evidence/claims.json`;
P0 без зелёного теста валит `./gradlew evidenceCheck`. Runtime- и P0 без зелёного теста валит `./gradlew evidenceCheck`. Runtime, migration,
migration-свидетельства — отдельные скрипты из `scripts/`. mutation и browser E2E — отдельные скрипты из `scripts/`; baseline —
`docs/evidence/baseline-2026-10-27.md`.
- CI merge gate — `.gitlab-ci.yml`: `./gradlew --no-daemon test ktlintCheck detekt evidenceCheck` - CI merge gate — `.gitlab-ci.yml`: `./gradlew --no-daemon test ktlintCheck detekt evidenceCheck`
на push/MR. Runner должен разрешать privileged `docker:dind` для Testcontainers. на push/MR. Runner должен разрешать privileged `docker:dind` для Testcontainers.

View File

@@ -294,9 +294,10 @@ upgrade-тест миграций, видимость активов и deploy-r
## 7. LDD baseline ## 7. LDD baseline
После этапа 6 текущая функциональность проверена через LDD-контур: После этапа 6 текущая функциональность проверена через LDD-контур:
реестр `docs/evidence/claims.json` (31 claim, 19 P0 / 12 P1), gate реестр `docs/evidence/claims.json` (34 claim, 19 P0 / 15 P1), gate
`./gradlew evidenceCheck`, upgrade-скрипт и runtime-smoke полного стека. `./gradlew evidenceCheck`, upgrade-скрипт, runtime-smoke, mutation testing
Результат: **31/31 claims proven, P0 gaps = 0**, 267 тестов, upgrade с и браузерный Playwright E2E. Результат: **34/34 claims proven, P0 gaps = 0**,
master-схемы и E2E-поток «админ → группа → курс → преподаватель → лаба» 273 теста; mutation strength `CourseAccessService` 75%,
проходят. Подробности и остаточные ограничения — `PromotionPlanner` 69%; browser E2E 3/3. E2E нашёл и закрыл реальный дефект
Jackson 3/Kotlin defaults. Подробности и остаточные ограничения —
[`docs/evidence/baseline-2026-10-27.md`](evidence/baseline-2026-10-27.md). [`docs/evidence/baseline-2026-10-27.md`](evidence/baseline-2026-10-27.md).

View File

@@ -44,16 +44,27 @@
# 4. Проверка upgrade с master-схемы # 4. Проверка upgrade с master-схемы
./scripts/ldd-migration-upgrade.sh ./scripts/ldd-migration-upgrade.sh
# 5. Mutation testing критичных P0-компонентов
./scripts/ldd-mutation.sh
# 6. Браузерный E2E (Playwright + Chromium)
./scripts/ldd-browser.sh
``` ```
Для E2E один раз установите зависимости: `cd e2e && npm install`.
Mutation harness использует JUnit 4: JUnit5-плагин PIT несовместим с JUnit
Platform 6 из Spring Boot 4.
Отчёт: `build/reports/evidence/index.md`. Отчёт: `build/reports/evidence/index.md`.
## Правила ## Правила
1. Новое P0-требование без свидетельства не мержится. 1. Новое P0-требование без свидетельства не мержится.
2. Свидетельство должно быть воспроизводимым в CI, а не «проверил руками». 2. Свидетельство должно быть воспроизводимым в CI, а не «проверил руками».
3. Тест должен падать при поломке соответствующей логики; для критичных 3. Тест должен падать при поломке соответствующей логики. Для критичных
пакетов позже добавим mutation testing. пакетов это измеряется mutation testing: сейчас `CourseAccessService` —
75% test strength, `PromotionPlanner` — 69%.
4. Один тест может подтверждать несколько claims, но claim не должен 4. Один тест может подтверждать несколько claims, но claim не должен
опираться на тест, который проверяет только реализацию. опираться на тест, который проверяет только реализацию.
5. `limitations` обязателен: LDD не должен создавать иллюзию полного 5. `limitations` обязателен: LDD не должен создавать иллюзию полного
@@ -65,12 +76,21 @@
## Текущий baseline ## Текущий baseline
Первый прогон LDD выполнен 2026-10-27: Первый LDD-цикл выполнен 2026-10-27/28:
- 267 автоматических тестов, 0 failures/errors; - **273 автоматических теста**, 0 failures/errors;
- 33 claims: P0 — доступы, повышение, жизненный цикл, профиль/скачивание, - **34 claims**: 19 P0 + 15 P1. P0 — доступы, повышение, жизненный цикл,
материалы/активы, миграция V13, аудит; P1 — группы, авторство, UI, профиль/скачивание, материалы/активы, миграция V13, аудит; P1 — группы,
контракты, импорт, копирование лаб, runtime. авторство, UI, контракты, импорт, копирование лаб, runtime, mutation и
- Runtime-smoke и master-upgrade вынесены в отдельные скрипты. browser E2E;
- mutation testing: `CourseAccessService` 75% test strength,
`PromotionPlanner` 69%;
- Playwright: 3 сценария (admin, teacher, student/anonymous), все зелёные;
- runtime-smoke, master-upgrade, mutation и browser E2E вынесены в отдельные
скрипты.
Результаты и найденные пробелы — в `baseline-2026-10-27.md`. В ходе E2E найден и исправлен реальный дефект: Jackson 3 не применял
Kotlin-модуль, поэтому DTO с default-значениями требовали все поля JSON
(например, создание студента без `firstName`/`basis` давало 400).
Результаты и остаточные ограничения — в `baseline-2026-10-27.md`.

View File

@@ -1,18 +1,19 @@
# LDD baseline: 2026-10-27 # LDD baseline: 2026-10-27/28
Первый прогон доказательной проверки текущей функциональности LMS. Первый и второй LDD-циклы проверки текущей функциональности LMS.
Код приложения в этом прогоне не менялся; добавлены реестр claims, gate Добавлены реестр claims, gate `evidenceCheck`, runtime/migration/mutation
`evidenceCheck`, runtime- и migration-скрипты. скрипты и браузерный E2E на Playwright. В ходе проверки найден и исправлен
реальный дефект Jackson 3.
## 1. Что проверялось ## 1. Что проверялось
Реестр: `docs/evidence/claims.json`, 31 утверждение. Реестр: `docs/evidence/claims.json`, **34 утверждения**.
| Критичность | Claims | Proven | Gaps | | Критичность | Claims | Proven | Gaps |
|---|---:|---:|---:| |---|---:|---:|---:|
| P0 | 19 | 19 | 0 | | P0 | 19 | 19 | 0 |
| P1 | 12 | 12 | 0 | | P1 | 15 | 15 | 0 |
| **Итого** | **31** | **31** | **0** | | **Итого** | **34** | **34** | **0** |
Домены: Домены:
@@ -24,8 +25,9 @@
- материалы и активы; - материалы и активы;
- миграция V13 и полный upgrade с master-схемы; - миграция V13 и полный upgrade с master-схемы;
- аудит: токен, admin-only, сохранность после удаления, representative-хуки; - аудит: токен, admin-only, сохранность после удаления, representative-хуки;
- группы курса, авторство материалов, ведомость, UI/контракты, импорт, копирование лаб; - группы курса, авторство материалов, ведомость, UI/контракты, импорт,
- runtime-smoke полного стека. копирование лабораторных;
- runtime-smoke, mutation testing, браузерный E2E.
## 2. Команды и результаты ## 2. Команды и результаты
@@ -35,7 +37,7 @@
./gradlew test --rerun-tasks ./gradlew test --rerun-tasks
``` ```
Результат: **267 тестов, 0 failures, 0 errors, 0 skipped**. Результат: **273 теста, 0 failures, 0 errors, 0 skipped**.
`ktlintCheck` и `detekt` — зелёные. `ktlintCheck` и `detekt` — зелёные.
### 2.2. LDD gate ### 2.2. LDD gate
@@ -44,7 +46,7 @@
./gradlew evidenceCheck ./gradlew evidenceCheck
``` ```
Результат: **31/31 claims proven, P0 gaps = 0**. Результат: **34/34 claims proven, P0 gaps = 0**.
Отчёт: `build/reports/evidence/index.md`. Отчёт: `build/reports/evidence/index.md`.
Gate устроен так: Gate устроен так:
@@ -94,49 +96,94 @@ identity `V4–V10`, academic `V6–V12`, progress `V13`.
- чужой преподаватель получает `403` на курс, лабу и аудит; - чужой преподаватель получает `403` на курс, лабу и аудит;
- админ видит audit-события `COURSE_CREATE`, `TEACHER_CREATE`, - админ видит audit-события `COURSE_CREATE`, `TEACHER_CREATE`,
`COURSE_TEACHER_ASSIGN`, `COURSE_GROUP_ATTACH`, `LAB_CREATE`; `COURSE_TEACHER_ASSIGN`, `COURSE_GROUP_ATTACH`, `LAB_CREATE`;
- web `/login` отдаёт `200`, публичное дерево материалов доступно, курсовая - web `/login` отдаёт `200`, публичное дерево материалов доступно, курсовые
материалы анонимно — `401`. материалы анонимно — `401`.
Результат: **PASS**, evidence: `build/evidence/runtime.json`. Результат: **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}`.
Результат: **3/3 passed**, evidence: `build/evidence/browser.json`.
### 2.7. Найденный дефект
Первый 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. Что это доказывает ## 3. Что это доказывает
- Критичные P0-инварианты доступа, повышения, жизненного цикла, профиля, - Критичные P0-инварианты доступа, повышения, жизненного цикла, профиля,
материалов, миграции и аудита имеют зелёные автоматические свидетельства. материалов, миграции и аудита имеют зелёные автоматические свидетельства.
- Приложение собирается, мигрируется с master-схемы и поднимается полным - Приложение собирается, мигрирует с master-схемы и поднимается полным
стеком на чистой БД. стеком на чистой БД.
- Ключевой доменный поток «админ → группа → курс → преподаватель → лаба» - Ключевой доменный поток «админ → группа → курс → преподаватель → лаба»
проходит через реальные HTTP/gateway/БД, а не только через mock. проходит через реальные HTTP/gateway/БД и браузер.
- Чужой преподаватель не получает доступ к курсу/лабе/аудиту на реальном стеке. - Чужой преподаватель не получает доступ к курсу/лабе/аудиту на реальном стеке.
- Аудит пишется и читается; upgrade не теряет синтетические данные. - Аудит пишется и читается; upgrade не теряет синтетические данные.
- Мутационная прочность критичных компонентов измерена, а не заявлена.
- Реальный дефект DTO/Jackson найден именно E2E-контуром и закрыт тестом.
## 4. Чего это не доказывает ## 4. Чего это не доказывает
1. **Нет браузерного E2E.** Thymeleaf-тесты проверяют HTML, но не реальные 1. **Нет нагрузочных и конкурентных испытаний.** Advisory locks и гонки
клики/JS/CSRF/редиректы в браузере.
2. **Нет нагрузочных и конкурентных испытаний.** Advisory locks и гонки
проверены кодом и unit/integration-тестами, но не под нагрузкой. проверены кодом и unit/integration-тестами, но не под нагрузкой.
3. **Нет mutation testing.** Сила тестов измерена косвенно; следующий шаг — 2. **Mutation testing не 100%.** Остаются эквивалентные мутанты и
PIT на `CourseAccessService`, `PromotionService`, `StudentProfileService`. Kotlin/Spring-специфичные мутации; PIT harness — JUnit 4, а не JUnit 5.
4. **Нет property-based/model-based проверки повышения.** Один сценарный тест 3. **Property-based тесты покрывают не все ветки.** Есть генераторы для
не покрывает все комбинации курсов, степеней и академ-переходов. матрицы доступа и планировщика повышения, но не для транзакционного
apply/rollback и конкурентных сценариев.
4. **Браузерный E2E — один Chromium и один сценарий на роль.** Нет
визуальной регрессии, мобильных размеров, Safari/Firefox.
5. **Legacy-активы без `article_assets` остаются публичными.** 5. **Legacy-активы без `article_assets` остаются публичными.**
6. **JWT живёт до 30 дней.** Web перепроверяет статус, прямой API — нет. 6. **JWT живёт до 30 дней.** Web перепроверяет статус, прямой API — нет.
7. **Ведущие нули номера группы нормализуются** (`01` → `1`). 7. **Ведущие нули номера группы нормализуются** (`01` → `1`).
8. **Нет пагинации/keyset** для части списков и N+1 в отдельных экранах. 8. **Нет пагинации/keyset** для части списков и N+1 в отдельных экранах.
9. **Runtime-smoke не входит в unit-CI**; он запускается отдельным скриптом 9. **Runtime/mutation/browser E2E не входят в unit-CI**; это release-скрипты.
перед релизом.
## 5. Вывод ## 5. Вывод
Текущая функциональность прошла первый LDD-контур: **P0 gaps = 0**, Текущая функциональность прошла LDD-контур: **34/34 claims proven, P0 gaps = 0**,
полный стек и upgrade работают. Это достаточное основание продолжать 273 теста, upgrade, mutation baseline и браузерный E2E зелёные. Это
доработки, но не «формальное доказательство всей системы». Следующий цикл достаточное основание продолжать доработки, но не «формальное доказательство
LDD должен добавить: всей системы».
1. mutation testing для критичных пакетов; Следующий цикл LDD:
2. property-based тесты повышения и матрицы доступа;
3. браузерный E2E (Playwright) для ведомости, профиля и материалов; 1. нагрузочный smoke на чтение ведомости/профиля и конкурентный apply/rollback;
4. нагрузочный smoke на чтение ведомости/профиля; 2. property-based/model-based тесты транзакционного повышения;
5. автоматический runtime-smoke в release-пайплайне. 3. расширение browser E2E (студенческая сдача, публикация оценки, мобильный вид);
4. автоматический release-пайплайн с runtime/mutation/browser evidence.