# Проект: проверка API-CORE-1 Редакция QA Orbit · 2026-10-28.1 API-CORE-1 — независимая спецификация локального учебного стенда QA Orbit. Все данные синтетические. Она не описывает production-портал и не заменяет OD-1/OD-API-1 из курсов ИИ. A1. Bearer-токены стенда: demo-anna → u-a/north/user; demo-boris → u-b/north/user; demo-vera → u-v/north/editor; demo-oleg → u-o/south/editor. Отсутствующий/неверный токен → 401, error.code=UNAUTHENTICATED, WWW-Authenticate: Bearer realm="qa-orbit-lab". Это публичные учебные значения, не способ аутентификации реального продукта. A2. POST /tasks: Content-Type application/json, JSON object только с title, description, priority. Title обязателен: строка 1–80 кодовых точек, без trim при сохранении. Description необязателен, по умолчанию "", строка 0–500 кодовых точек Unicode. Priority необязателен, по умолчанию normal, enum low | normal | high. null, неверный тип/длина, неизвестное поле → 422 INVALID_TASK. Невалидный JSON → 400 MALFORMED_JSON. Другой/отсутствующий Content-Type → 415 JSON_REQUIRED. Проверяется сначала A1, затем media type, JSON syntax, поля. A3. Успешное создание → 201, Location: /tasks/{id}; body={id,team,authorId,title,description,priority,state}. ID выдаёт сервер, team/authorId берутся из токена, state=draft. Все поля сохраняются точно, кроме явно указанных defaults. ID уникален внутри процесса. Пример начальных ID не является обещанием последующих ID. A4. GET /tasks/{id}: автор читает свой draft; published читают все участники той же команды. Чужой draft, другая команда и неизвестный ID → 404 NOT_FOUND. Успех → 200 и полное тело задачи. Чужой editor не получает права читать draft. A5. POST /tasks/{id}/publish без тела: порядок A1 → существование/команда (404 NOT_FOUND) → автор ИЛИ editor (403 FORBIDDEN) → state=draft (иначе 409 ALREADY_PUBLISHED) → title.trim() непуст (иначе 422 BLANK_TITLE). Успех → 200, тот же ID, меняется только state на published. Результат предыдущей проверки определяет ошибку при нескольких нарушениях. A6. Все отказы сохраняют набор задач и поля без изменений. GET не изменяет задачи. Все ответы JSON, Content-Type application/json; charset=utf-8, Cache-Control:no-store. Ошибка имеет форму {"error":{"code":"..."}}. A7. У POST /tasks нет ключа идемпотентности и автоматического устранения дублей: два одинаковых успешных запроса создают две записи. Потеря ответа не доказывает, что создание не состоялось. SLA/нагрузка/пагинация/удаление не входят в контракт. A8. Управление только учебной моделью: GET /__lab/snapshot и POST /__lab/reset требуют X-Lab-Key:local-only. Снимок содержит все синтетические задачи; reset восстанавливает 4 начальные и счётчик. Это средства проверки лаборатории, не публичные методы продуктового API. Стенд слушает только 127.0.0.1; данные исчезают при остановке. Начальные данные после reset: t1 north/u-a/title="План"/draft/normal; t2 north/u-a/title="Релиз"/published/high; t3 north/u-a/title=" "/draft/normal; t4 south/u-o/title="Юг"/draft/low. Description у всех "". Офлайн-свидетельства для разбора: S1 Вера GET t1→200 с draft; S2 Борис publish t2→409; S3 Вера publish t1→200 и лишняя t5; S4 Анна publish t3→422 без мутации. D1 connection refused без HTTP-status; D2 Борис publish t2→403 при ожидании 409; D3 title:null→422+лишняя t5; D4 два корректных Create→201/t5 и 201/t6. Это независимые учебные трассы, не фактический вывод скачиваемой лаборатории. Для динамического режима используйте lab и наблюдайте свой реальный результат. ## Задание - Соберите 12–18 сценариев с позитивами, тремя уровнями валидации, ролями/командами и переходами. - Включите проверку 401+challenge, defaults, точного title/author/Location, инвариантов отказа и публикации. - Реализуйте либо опишите цепочку Create→Read→Publish→Repeat с ID текущего запуска. - Добавьте собственный класс данных и объясните его риск. - Сдайте отчёт: режим, окружение, фактические статусы или Not run, дефекты/ошибки тестов и ограничения. ## Критерии - Есть прослеживаемость A-правило→сценарий→assertion→свидетельство. - Оракулы учитывают порядок ошибок и разделение чтения/публикации. - Нет зависимости от случайного ID и прошлого запуска. - Отказы и успешная публикация проверяют поля/число записей. - Результат локальной модели не выдан за проверку production. ## Ориентир после самостоятельной попытки Каркас: 1) без токена GET→401+challenge; 2) Create с title=" План "→201/defaults/u-a/точный title/Location; 3) Read полученного ID→200; 4) text/plain→415; 5) обрезанный JSON→400; 6) title:null→422; 7) title × 81→422; 8) unknown authorId→422; 9) чужой draft Борис→404; 10) published Борис→200; 11) другая команда→404; 12) Борис publish→403; 13) Анна публикация пробельного title→422; 14) Вера publish t1→200; 15) повторпод Анной→409; 16) собственное расширение description:null→422 либо😀×80→201. Снимки подтверждают отсутствие мутаций у отказов и единственное изменение state при успехе. Dynamic report содержит реальный вывод; offline report оставляет новые запросы — Not run и правильно классифицирует S1/S2/S3/D3 как нарушения трасс, D2 как неверный тест, D1 как препятствие, D4 как допустимый повтор. Нельзя перепутать выданные ошибочные трассы с результатом корректного локального стенда. Локальный запуск, подготовка, snapshot/reset и остановка описаны в README.md. Самопроверка на сайте не является внешней экспертизой проекта.