Files
LMS/docs/evidence/claims.json

503 lines
34 KiB
JSON
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.

{
"version": 1,
"description": "LDD claims для текущей функциональности LMS. P0 без зелёного свидетельства валит ./gradlew evidenceCheck.",
"claims": [
{
"id": "LDD-ACCESS-001",
"title": "Преподаватель не получает доступ к чужому курсу, лабе, студенту или группе",
"criticality": "P0",
"status": "active",
"requirement": "docs/07-groups-courses.md, §5",
"claim": "Для любого преподавателя T и ресурса R чужого курса сервис возвращает 403/404 и не отдаёт данные R.",
"oracle": "HTTP-статус отказа и отсутствие данных в ответе",
"evidence": [
"ru.ysu.lms.academic.course.CourseAccessServiceTest#teacher cannot access a foreign course()",
"ru.ysu.lms.academic.course.CourseRosterServiceTest#foreign teacher is forbidden()",
"ru.ysu.lms.progress.TeacherWriteAccessIntegrationTest#teacher is forbidden to grade foreign lab()",
"ru.ysu.lms.progress.TeacherWriteAccessIntegrationTest#teacher is forbidden to grade student from another course()"
],
"limitations": "Проверены основные API-точки; UI-навигация не является границей безопасности."
},
{
"id": "LDD-ACCESS-002",
"title": "Студент видит только свои курсы, группу и опубликованные данные",
"criticality": "P0",
"status": "active",
"requirement": "docs/07-groups-courses.md, §5",
"claim": "Студент чужой группы не получает доступ к курсу, а в своём профиле видит только опубликованные оценки и комментарии.",
"oracle": "403 для чужого курса; отсутствие неопубликованных данных в ответе",
"evidence": [
"ru.ysu.lms.academic.course.CourseAccessServiceTest#student cannot access course of a foreign group()",
"ru.ysu.lms.progress.StudentProfileIntegrationTest#student sees only published grade and comments of own profile()",
"ru.ysu.lms.progress.StudentProfileIntegrationTest#teacher cannot read or download student from group outside course but admin can()"
],
"limitations": "Студенческий BFF-профиль не является отдельной страницей; проверен профильный API."
},
{
"id": "LDD-ACCESS-003",
"title": "Анонимный доступ ограничен глобальными материалами ALL",
"criticality": "P0",
"status": "active",
"requirement": "docs/07-groups-courses.md, §6",
"claim": "Аноним не читает курсовые и приватные материалы/активы; публичное дерево содержит только глобальные главы audience=ALL.",
"oracle": "401/404 для приватного; 200 только для ALL; состав публичного дерева",
"evidence": [
"ru.ysu.lms.academic.content.CourseContentIntegrationTest#anonymous cannot read course content()",
"ru.ysu.lms.academic.content.CourseContentIntegrationTest#public tree contains only global chapters with ALL audience()",
"ru.ysu.lms.academic.content.ContentAssetAccessIntegrationTest#course asset requires authentication()",
"ru.ysu.lms.academic.content.ContentAssetAccessIntegrationTest#published global ALL asset stays public()"
],
"limitations": "Legacy-активы без article_assets остаются публичными и вынесены в отдельный риск."
},
{
"id": "LDD-ACCESS-004",
"title": "Администратор сохраняет полный доступ",
"criticality": "P0",
"status": "active",
"requirement": "docs/07-groups-courses.md, §5",
"claim": "Администратор не ограничен курсовой областью и может читать/писать любой курс и профиль.",
"oracle": "Успешный доступ к чужому курсу/лабе/студенту для ADMIN",
"evidence": [
"ru.ysu.lms.academic.course.CourseAccessServiceTest#admin bypasses checks and has no course restriction()",
"ru.ysu.lms.academic.course.CourseAccessServiceTest#admin my courses contains every course()",
"ru.ysu.lms.progress.TeacherWriteAccessIntegrationTest#admin keeps access without course scope checks()"
],
"limitations": "Проверены сервисные проверки, не все административные UI-маршруты."
},
{
"id": "LDD-ACCESS-005",
"title": "Внутренние API identity защищены сервисным токеном и не раскрывают учётные данные",
"criticality": "P0",
"status": "active",
"requirement": "docs/13-stage3-report.md, §3",
"claim": "Без корректного X-Internal-Token внутренние API возвращают 403; ответы не содержат паролей, tempPassword и лишних данных.",
"oracle": "403 на неверный/пустой токен; отсутствие чувствительных полей в JSON",
"evidence": [
"ru.ysu.lms.identity.internal.InternalControllerIntegrationTest#invalid token is forbidden()",
"ru.ysu.lms.identity.internal.InternalControllerIntegrationTest#groups response exposes no credentials or students()",
"ru.ysu.lms.identity.audit.AuditIntegrationTest#invalid or missing internal token is forbidden and writes nothing()"
],
"limitations": "Проверены контекст студента, состав группы, список групп и аудит."
},
{
"id": "LDD-ACCESS-006",
"title": "Преподаватель управляет лабораторными только своего курса",
"criticality": "P0",
"status": "active",
"requirement": "docs/07-groups-courses.md, §5",
"claim": "TEACHER может создавать и изменять лабы/уровни/варианты своего курса, но не чужого; STUDENT не может писать.",
"oracle": "200 для своего курса; 403 для чужого; 403 для студента",
"evidence": [
"ru.ysu.lms.academic.lab.LabTeacherAccessIntegrationTest#teacher cannot update lab of foreign course()",
"ru.ysu.lms.academic.lab.LabTeacherAccessIntegrationTest#teacher can create lab in own course()",
"ru.ysu.lms.academic.lab.LabTeacherAccessIntegrationTest#student cannot update or create labs()"
],
"limitations": "Импорт ZIP проверен отдельными тестами парсера/копирования."
},
{
"id": "LDD-PROM-001",
"title": "Dry-run повышения не меняет данные и дедуплицируется по году",
"criticality": "P0",
"status": "active",
"requirement": "docs/07-groups-courses.md, §7",
"claim": "Построение dry-run создаёт только план; данные групп/студентов не меняются; повторный запуск за год не создаёт дубль.",
"oracle": "Снимок данных до/после и количество запусков",
"evidence": [
"ru.ysu.lms.identity.promotion.PromotionServiceIntegrationTest#dry run only plans and does not change data()",
"ru.ysu.lms.identity.promotion.PromotionServiceIntegrationTest#scheduled dry run guard respects date and deduplicates by year()"
],
"limitations": "Проверено на синтетических данных Testcontainers."
},
{
"id": "LDD-PROM-002",
"title": "Применение повышения переводит группы и студентов по правилам",
"criticality": "P0",
"status": "active",
"requirement": "docs/07-groups-courses.md, §7",
"claim": "Apply повышает курс групп, выпускает на пределе и переводит академических студентов в целевую группу.",
"oracle": "Группы, статусы, зачисления и membership_history после apply",
"evidence": [
"ru.ysu.lms.identity.promotion.PromotionServiceIntegrationTest#apply promotes groups graduates and moves academic students()"
],
"limitations": "Проверен один сценарий; граничные сочетания требуют property-based тестов."
},
{
"id": "LDD-PROM-003",
"title": "Повторное применение повышения идемпотентно",
"criticality": "P0",
"status": "active",
"requirement": "docs/07-groups-courses.md, §7",
"claim": "Повторный apply того же run не создаёт повторных изменений и истории.",
"oracle": "Состояние и количество history-записей после первого и второго apply",
"evidence": [
"ru.ysu.lms.identity.promotion.PromotionServiceIntegrationTest#repeated apply is idempotent()"
],
"limitations": "Конкурентный apply проверяется advisory lock, но отдельного нагрузочного теста нет."
},
{
"id": "LDD-PROM-004",
"title": "Откат повышения восстанавливает состояние и обнаруживает конфликт",
"criticality": "P0",
"status": "active",
"requirement": "docs/07-groups-courses.md, §7",
"claim": "Rollback возвращает before-state; при ручной правке после apply сообщает конфликт и не затирает данные.",
"oracle": "Снимок before/after и 409 при конфликте",
"evidence": [
"ru.ysu.lms.identity.promotion.PromotionServiceIntegrationTest#rollback restores data and removes created target group()",
"ru.ysu.lms.identity.promotion.PromotionServiceIntegrationTest#rollback reports manual conflict()"
],
"limitations": "Проверены группы и студенты; rollback файлов/аудита не применим."
},
{
"id": "LDD-LIFE-001",
"title": "Жизненный цикл студента пишет историю и переводит зачисление",
"criticality": "P0",
"status": "active",
"requirement": "docs/07-groups-courses.md, §8",
"claim": "Академ/возврат/отчисление/архив/восстановление меняют статусы, зачисление и membership_history по правилам.",
"oracle": "Статус student/account, группа зачисления, membership_history",
"evidence": [
"ru.ysu.lms.identity.roster.StudentLifecycleIntegrationTest#academic leave creates target cohort group and records history()",
"ru.ysu.lms.identity.roster.StudentLifecycleIntegrationTest#return from academic leave moves to requested active group()",
"ru.ysu.lms.identity.roster.StudentLifecycleIntegrationTest#expel blocks login and keeps current enrollment for history()",
"ru.ysu.lms.identity.roster.StudentLifecycleIntegrationTest#archive blocks login and restore returns student to active group()",
"ru.ysu.lms.identity.roster.StudentLifecycleIntegrationTest#restore returns an expelled student to active group()"
],
"limitations": "Проверены основные переходы; массовые операции не автоматизированы."
},
{
"id": "LDD-LIFE-002",
"title": "Вход закрыт для отчисленных, архивных и закрытых групп",
"criticality": "P0",
"status": "active",
"requirement": "docs/07-groups-courses.md, §1.3",
"claim": "EXPELLED/GRADUATED/ARCHIVED студенты и архивные аккаунты не проходят login; активный студент проходит.",
"oracle": "Unauthorized/403 при login и active=false в /auth/me",
"evidence": [
"ru.ysu.lms.identity.roster.GroupServiceIntegrationTest#expelled student cannot login()",
"ru.ysu.lms.identity.roster.StudentLifecycleIntegrationTest#student in archived group cannot login()",
"ru.ysu.lms.identity.roster.StudentLifecycleIntegrationTest#student in active group can login()",
"ru.ysu.lms.identity.AuthServiceMeActiveTest#me is inactive for archived account()"
],
"limitations": "JWT с прежним сроком жизни остаётся остаточным риском."
},
{
"id": "LDD-PROFILE-001",
"title": "Профиль студента курса различает staff/student и публикацию",
"criticality": "P0",
"status": "active",
"requirement": "docs/07-groups-courses.md, §5.1",
"claim": "Преподаватель своего курса видит все лабы и неопубликованные данные; студент — только опубликованное; чужой преподаватель получает 403.",
"oracle": "Состав DTO профиля и HTTP-статус",
"evidence": [
"ru.ysu.lms.progress.StudentProfileIntegrationTest#teacher sees unpublished grade, authors and all submission attempts()",
"ru.ysu.lms.progress.StudentProfileIntegrationTest#student sees only published grade and comments of own profile()",
"ru.ysu.lms.progress.StudentProfileIntegrationTest#teacher of another course gets forbidden()"
],
"limitations": "Проверен API; UI-шаблон проверяется отдельно."
},
{
"id": "LDD-DOWNLOAD-001",
"title": "Скачивание сдачи ограничено курсом и студентом",
"criticality": "P0",
"status": "active",
"requirement": "docs/07-groups-courses.md, §5.1",
"claim": "Преподаватель скачивает только сдачи своего курса/своих студентов; сдача лабы другого курса отклоняется.",
"oracle": "ZIP для разрешённой сдачи; 403 для чужой лабы/студента",
"evidence": [
"ru.ysu.lms.progress.StudentProfileIntegrationTest#download rejects submission from another course lab and allows current course lab()",
"ru.ysu.lms.progress.TeacherLabPageAccessIntegrationTest#teacher downloads submission of own lab()",
"ru.ysu.lms.progress.TeacherLabPageAccessIntegrationTest#teacher is forbidden for foreign lab()"
],
"limitations": "Аудит скачивания проверяется отдельным claim."
},
{
"id": "LDD-CONTENT-001",
"title": "Курсовые материалы не утекают в публичное дерево",
"criticality": "P0",
"status": "active",
"requirement": "docs/07-groups-courses.md, §6",
"claim": "Курсовая глава недоступна через публичный article endpoint; студент видит только published; преподаватель видит hidden.",
"oracle": "404/отсутствие курсовой главы в public tree; состав courseTree",
"evidence": [
"ru.ysu.lms.academic.content.CourseContentIntegrationTest#course chapter is not exposed through public article endpoint()",
"ru.ysu.lms.academic.content.CourseContentIntegrationTest#student of course sees only published materials()",
"ru.ysu.lms.academic.content.CourseContentIntegrationTest#teacher of course sees published and hidden materials()"
],
"limitations": "Импорт и авторство проверяются отдельными тестами."
},
{
"id": "LDD-ASSET-001",
"title": "Видимость активов наследуется от статьи",
"criticality": "P0",
"status": "active",
"requirement": "docs/07-groups-courses.md, §6",
"claim": "Скрытый курсовой актив не отдаётся студенту, но доступен преподавателю; чужой курс получает 403; legacy без связи публичен.",
"oracle": "HTTP-статус и содержимое файла",
"evidence": [
"ru.ysu.lms.academic.content.ContentAssetAccessIntegrationTest#hidden course asset is not served to student but is served to teacher()",
"ru.ysu.lms.academic.content.ContentAssetAccessIntegrationTest#foreign teacher and student are forbidden for course asset()",
"ru.ysu.lms.academic.content.ContentAssetAccessIntegrationTest#legacy asset without article association stays public()"
],
"limitations": "Legacy-файлы без article_assets остаются публичными — отдельный остаточный риск."
},
{
"id": "LDD-MIG-001",
"title": "Миграция V13 идемпотентна",
"criticality": "P0",
"status": "active",
"requirement": "docs/16-stage6-report.md, §2.2",
"claim": "Повторное применение V13 не меняет схему и не падает.",
"oracle": "Повторный Flyway migrate и проверка колонок/индекса",
"evidence": [
"ru.ysu.lms.progress.migration.ProfileAuthorsMigrationTest#V13 profile authors migration is idempotent()"
],
"limitations": "Полный upgrade с master-схемы проверяется runtime-скриптом."
},
{
"id": "LDD-AUDIT-001",
"title": "Аудит защищён и доступен только администратору",
"criticality": "P0",
"status": "active",
"requirement": "docs/16-stage6-report.md, §2.3",
"claim": "Внутренняя запись требует X-Internal-Token; чтение /api/v1/audit требует ADMIN.",
"oracle": "403 без токена/для не-админа; 200 для админа",
"evidence": [
"ru.ysu.lms.identity.audit.AuditIntegrationTest#admin list requires admin role()",
"ru.ysu.lms.identity.audit.AuditIntegrationTest#invalid or missing internal token is forbidden and writes nothing()"
],
"limitations": "Проверены API; UI-страница проверяется отдельным шаблонным тестом."
},
{
"id": "LDD-AUDIT-002",
"title": "Аудит переживает удаление сущности и сохраняет поля",
"criticality": "P0",
"status": "active",
"requirement": "docs/07-groups-courses.md, §5.2",
"claim": "Событие аудита сохраняется после удаления студента/преподавателя и корректно отдаётся в списке.",
"oracle": "Наличие строки после delete; поля id/action/entity/occurredAt",
"evidence": [
"ru.ysu.lms.identity.audit.AuditIntegrationTest#identity hooks record teacher create and student delete that survives deletion()",
"ru.ysu.lms.identity.audit.AuditIntegrationTest#internal write is listed newest first with all fields()"
],
"limitations": "Проверены identity-хуки; cross-service хуки проверяются отдельными тестами."
},
{
"id": "LDD-ACCESS-007",
"title": "Преподаватель управляет группами своего курса",
"criticality": "P1",
"status": "active",
"requirement": "docs/07-groups-courses.md, §5",
"claim": "TEACHER привязывает/отвязывает активные группы только своего курса; чужой преподаватель и студент получают 403.",
"oracle": "200 и history-запись для своего курса; 403 для чужого",
"evidence": [
"ru.ysu.lms.academic.course.CourseGroupTeacherAccessTest#teacher sees available groups, attaches and detaches on own course()",
"ru.ysu.lms.academic.course.CourseGroupTeacherAccessTest#foreign teacher cannot list attach or detach groups()"
],
"limitations": "Проверено API; UI-форма — шаблонным тестом."
},
{
"id": "LDD-ACCESS-008",
"title": "Преподаватель авторствует материалы только своего курса",
"criticality": "P1",
"status": "active",
"requirement": "docs/07-groups-courses.md, §5",
"claim": "TEACHER создаёт/меняет/публикует главы, разделы и статьи своего курса; глобальные материалы — только ADMIN; чужой курс — 403.",
"oracle": "200 для своего курса; 403 для чужого; global routes только ADMIN",
"evidence": [
"ru.ysu.lms.academic.content.CourseContentAuthoringIntegrationTest#teacher creates chapter section and article in own course()",
"ru.ysu.lms.academic.content.CourseContentAuthoringIntegrationTest#foreign teacher cannot author course content()",
"ru.ysu.lms.academic.content.CourseContentAuthoringIntegrationTest#global chapter authoring stays admin only()"
],
"limitations": "Импорт ZIP остаётся админским; это осознанное ограничение."
},
{
"id": "LDD-ACCESS-009",
"title": "Ведомость преподавателя не показывает админские операции",
"criticality": "P1",
"status": "active",
"requirement": "docs/13-stage3-report.md, §4",
"claim": "В teacher-view скрыты пароли, аттестации и жизненный цикл; админский вид не меняется; админские URL закрыты интерсептором.",
"oracle": "Состав HTML и redirect для teacher",
"evidence": [
"ru.ysu.lms.web.admin.TeacherGradebookTemplateTest#teacher gradebook has no admin-only controls()",
"ru.ysu.lms.web.admin.TeacherGradebookTemplateTest#admin view is used when teacherView attribute is missing()",
"ru.ysu.lms.web.session.AdminInterceptorTest#teacher is redirected from admin-only group operations()"
],
"limitations": "Это UI-защита; серверные проверки — в LDD-ACCESS-001."
},
{
"id": "LDD-LIFE-003",
"title": "Удаление требует усиленного подтверждения",
"criticality": "P1",
"status": "active",
"requirement": "docs/07-groups-courses.md, §11",
"claim": "DELETE студента без совпадения confirm с login/ФИО отклоняется; корректный confirm удаляет.",
"oracle": "400 при неверном confirm; успешное удаление при верном",
"evidence": [
"ru.ysu.lms.identity.roster.StudentLifecycleIntegrationTest#delete requires confirm equal to login or full name()"
],
"limitations": "Проверен сервис; UI-диалог — шаблонным тестом."
},
{
"id": "LDD-PROM-005",
"title": "Отмена устаревшего dry-run разрешает перестроить план",
"criticality": "P1",
"status": "active",
"requirement": "docs/16-stage6-report.md, §2.3",
"claim": "Cancel переводит PLANNED dry-run в FAILED/CANCELLED; после этого можно построить новый план за год.",
"oracle": "Статус run и создание нового dry-run",
"evidence": [
"ru.ysu.lms.identity.promotion.PromotionServiceIntegrationTest#cancel marks planned dry run and allows rebuild()"
],
"limitations": "Конкурентный cancel/apply защищён advisory lock, отдельного теста нет."
},
{
"id": "LDD-IMPORT-001",
"title": "Импорт групп валидирует файл и не применяется частично",
"criticality": "P1",
"status": "active",
"requirement": "docs/07-groups-courses.md, §9",
"claim": "Ошибочные строки блокируют импорт целиком; корректный шаблон и дубли № распознаются.",
"oracle": "applied=false и отсутствие изменений при ошибках; отчёт парсера",
"evidence": [
"ru.ysu.lms.identity.roster.GroupServiceIntegrationTest#does not apply import when there are row errors()",
"ru.ysu.lms.identity.roster.StudentImportParserTest#parses new template and splits full name()",
"ru.ysu.lms.identity.roster.StudentImportParserTest#reports duplicate student number()"
],
"limitations": "Старый формат не поддерживается; ведущие нули нормализуются."
},
{
"id": "LDD-LAB-002",
"title": "Копирование лабораторной не переносит прогресс и требует другой курс",
"criticality": "P1",
"status": "active",
"requirement": "docs/07-groups-courses.md, §10",
"claim": "Копия создаёт новые уровни/варианты в целевом курсе, не копирует оценки/сдачи; тот же/архивный курс отклоняется.",
"oracle": "Состав копии и отсутствие progress-строк; 400 для same/archived",
"evidence": [
"ru.ysu.lms.academic.lab.LabCopyIntegrationTest#copies lab with levels and variants into another course()",
"ru.ysu.lms.academic.lab.LabCopyIntegrationTest#copy rejects the source course as target()",
"ru.ysu.lms.academic.lab.LabCopyIntegrationTest#copy rejects an archived target course()"
],
"limitations": "Проверено на Testcontainers; UI-копирование — шаблонным тестом."
},
{
"id": "LDD-CONTRACT-001",
"title": "DTO-контракты web и сервисов совпадают",
"criticality": "P1",
"status": "active",
"requirement": "docs/09-teacher-student-profile.md",
"claim": "Ключевые JSON-контракты профиля, состава группы, аудита и повышения десериализуются web-слоем без потери полей.",
"oracle": "JsonIgnoreProperties + значения полей после десериализации",
"evidence": [
"ru.ysu.lms.web.profile.ProfileDtoJsonTest#deserializes profile contract()",
"ru.ysu.lms.web.api.CourseGroupRosterDtoTest#deserializes course group roster contract()",
"ru.ysu.lms.web.api.AuditDtoTest#deserializes audit event list with nulls()",
"ru.ysu.lms.web.api.PromotionDtoTest#deserializes promotion detail with item states and result()",
"ru.ysu.lms.identity.roster.TeacherIntegrationTest#student creation accepts omitted optional json fields()"
],
"limitations": "Это smoke-контракты, не consumer-driven contracts."
},
{
"id": "LDD-UI-001",
"title": "Ключевые страницы содержат нужные действия и не раскрывают лишнего",
"criticality": "P1",
"status": "active",
"requirement": "docs/16-stage6-report.md, §3.3",
"claim": "Шаблоны ведомости, материалов и аудита рендерят ожидаемые формы/ссылки и экранируют данные.",
"oracle": "Содержимое HTML и отсутствие запрещённых элементов",
"evidence": [
"ru.ysu.lms.web.teacher.TeacherCourseContentTemplateTest#content page renders create forms and full tree()",
"ru.ysu.lms.web.profile.StudentProfileTemplateTest#renders student profile with labs, comments and downloads()",
"ru.ysu.lms.web.admin.AdminAuditTemplateTest#renders audit events with labels and filter()"
],
"limitations": "Thymeleaf-тесты не заменяют браузерный E2E."
},
{
"id": "LDD-AUDIT-003",
"title": "Критичные действия progress пишут аудит",
"criticality": "P1",
"status": "active",
"requirement": "docs/07-groups-courses.md, §5.2",
"claim": "Оценка и публикация оценки создают audit-событие с actor из JWT и корректными идентификаторами.",
"oracle": "Вызов AuditClient с ожидаемыми action/entity/student/course",
"evidence": [
"ru.ysu.lms.progress.ProgressControllerAuditTest#grade write records audit entry for actor from jwt()",
"ru.ysu.lms.progress.ProgressControllerAuditTest#publication records student count()",
"ru.ysu.lms.identity.audit.AuditIntegrationTest#action filter and limit are applied()"
],
"limitations": "Проверены representative-хуки; остальные actions проверяются кодом и smoke."
},
{
"id": "LDD-MIG-002",
"title": "Upgrade с master-схемы применяет миграции ветки",
"criticality": "P1",
"status": "active",
"requirement": "docs/16-stage6-report.md, §2.2",
"claim": "Схема master + синтетические данные → миграции identity V4–V10, academic V6–V12, progress V13; V10 audit создаётся, V13 идемпотентна.",
"oracle": "Успешное применение и postflight-наличие таблиц/колонок/индексов",
"runtime": [
"migration.master_upgrade"
],
"limitations": "Запускается отдельным скриптом на одноразовой БД; не входит в unit-CI."
},
{
"id": "LDD-RUNTIME-001",
"title": "Полный стек поднимается и проходит E2E smoke",
"criticality": "P1",
"status": "active",
"requirement": "docs/16-stage6-report.md, §3.3",
"claim": "На чистой БД стартуют все сервисы, health=UP, admin setup/login работает, создаются группа/курс/преподаватель/лаба, чужой преподаватель получает 403, аудит доступен.",
"oracle": "HTTP health/status/JSON на реальном стеке",
"runtime": [
"runtime.stack_health",
"runtime.admin_setup_login",
"runtime.course_flow",
"runtime.foreign_teacher_denied",
"runtime.audit_visible",
"runtime.web_login_page"
],
"limitations": "Smoke не заменяет полный UI E2E и нагрузочные тесты."
},
{
"id": "LDD-MUTATION-001",
"title": "Мутационная прочность матрицы доступа",
"criticality": "P1",
"status": "active",
"requirement": "docs/evidence/README.md",
"claim": "PIT по CourseAccessService убивает не менее 70% покрытых мутаций.",
"oracle": "PIT mutations.xml: killed / covered",
"runtime": [
"mutation.course_access"
],
"limitations": "PIT 1.20 + JUnit4 harness; Kotlin/Spring-специфичные мутации и эквивалентные мутанты не входят в цель."
},
{
"id": "LDD-MUTATION-002",
"title": "Мутационная прочность планировщика повышения",
"criticality": "P1",
"status": "active",
"requirement": "docs/evidence/README.md",
"claim": "PIT по PromotionPlanner убивает не менее 60% покрытых мутаций.",
"oracle": "PIT mutations.xml: killed / covered",
"runtime": [
"mutation.promotion_planner"
],
"limitations": "Проверяется планировщик, не транзакционный apply/rollback (они покрыты интеграционными тестами)."
},
{
"id": "LDD-BROWSER-001",
"title": "Браузерный E2E админа, преподавателя и студента",
"criticality": "P1",
"status": "active",
"requirement": "docs/evidence/README.md",
"claim": "Playwright на реальном стеке: admin видит курс и аудит, teacher открывает курс/ведомость/профиль и создаёт главу, аноним и студент не попадают в админку.",
"oracle": "Playwright assertions на DOM/URL",
"runtime": [
"browser.e2e"
],
"limitations": "Один Chromium, один сценарий на роль; визуальная регрессия и мобильные размеры не проверяются."
}
]
}