Учебный гайд: Прикладная часть 7. Specification CI: спецификация как исполняемый артефакт

Урок 3 из 5 в модуле «Прикладная часть 7. Specification CI: спецификация как исполняемый артефакт»
Вы просматриваете урок без входа. Войдите, чтобы сохранять прогресс и проходить тесты.

Тема: Прикладная часть 7. Specification CI: спецификация как исполняемый артефакт

Уровень сложности: Средний

Расчётное время изучения: 4-6 часов (теория + практика с runnable-примерами)

Предварительные требования: Базовое понимание Git и GitHub Actions

Опыт работы с Markdown-документами требований (requirements.md, plan.md)

Знакомство с JSON Schema

Прохождение части 9 первого тома (валидация фактов) и части 16 (командное ревью)

Базовый Python для запуска скриптов проверки

Цели обучения: Настроить локальный шлюз спецификации (Spec CI), который блокирует слияние при нарушениях покрытия, области охвата или схемы данных

Построить воспроизводимый граф трассировки requirements → plan с идентификаторами REQ-* и полем implements

Сформулировать диагностические сообщения CI, содержащие файл, строку, идентификатор правила и конкретное действие для исправления

Интегрировать spec_gate в защиту ветки GitHub, чтобы зелёные модульные тесты не могли обойти смысловую проверку

Создать отрицательные фикстуры для JSON Schema и объяснить, почему их предсказуемый отказ защищает контракт

Обзор: Эта глава превращает спецификацию из статичного текста в исполняемый арбитр репозитория. Шлюз спецификации (Spec CI) — это контур GitHub Actions, который на каждый push и pull_request проверяет три слоя: покрытие требований планом (coverage), соответствие плана доменной модели (scope) и корректность примеров данных (schema). Ключевой принцип: спор о качестве спецификации сводится к конкретной строке, правилу и действию. Команда получает воспроизводимый механизм блокировки, а ревьюер проверяет смысл правки, а не расследует логи CI. Глава начинается с локального runnable-примера на incident payload, а затем масштабируется до production-контура с branch protection.

Ключевые концепции: Spec ci (шлюз спецификации): Контур непрерывной интеграции, который проверяет requirements.md, plan.md, validation.md и API-контракты как исполняемые артефакты. Блокирует слияние при трёх классах нарушений: невыполнение требований, выход за границы (out-of-scope), ошибки JSON Schema. Главный термин первого прохода; остальные термины вводятся по мере появления в скриптах.

Gate (шлюз): Обязательная проверка в CI, без прохождения которой слияние невозможно. В отличие от обычных тестов, spec_gate проверяет смысловую целостность, а не только корректность кода. Должен быть помечен как обязательный в настройках защиты ветки.

Coverage-check (проверка покрытия): Построение графа трассировки requirements → plan через стабильные идентификаторы REQ-* и поле implements. Каждая пользовательская история должна иметь реализующую задачу, каждая задача — обратную ссылку. Ошибки: orphan requirement (требование без задачи) и rogue task (задача без требования).

Scope-check (проверка области охвата): Детектор выхода за границы доменной модели. Проверяет, что действия в plan.md разрешены в incident-response domain: acknowledge, escalate, annotate, rollback, notify_on_call. Учитывает актёра, endpoint и условие запуска. Блокирует автономные операции вроде force_resolve_without_operator.

Schema-check (проверка схемы): Валидация JSON-фикстур из validation.md против JSON Schema. Два направления: валидные примеры проходят, отрицательные падают предсказуемо. Если отрицательная фикстура проходит — схема слишком мягкая.

Fixture (фикстура): Пример входных данных, извлекаемый из validation.md для проверки контракта. Валидные фикстуры подтверждают корректную работу, отрицательные — защищают от регрессий схемы.

Spec gate (итоговая задача ci): Завершающий job в workflow, который требует успешного выполнения coverage, scope и schema. Именно эта задача должна быть помечена обязательной в branch protection, иначе зелёные модульные тесты обойдут смысловую проверку.

Json-диагностика: Формат отклонений CI, рассчитанный на быстрое исправление без расследования. Четыре обязательных элемента: понятная причина, ссылка на файл и строку, идентификатор правила, конкретное действие.

Runnable-пример: Локальный учебный кейс на incident payload, который можно запустить без GitHub Actions. Содержит check_coverage.py и validate_schema.py для демонстрации принципов шлюза перед внедрением полноценного CI.

Практические упражнения: Название: Локальный прогон шлюза покрытия

Проблема: Перейдите в директорию book2/examples/spec-ci и запустите скрипт проверки покрытия. Затем намеренно нарушьте связь: добавьте в requirements.md историю REQ-999 без реализующей задачи в plan.md. Запустите скрипт снова и проанализируйте диагностику.

Решение: 1. cd book2/examples/spec-ci

  1. python3 scripts/check_coverage.py --requirements requirements.md --plan plan.md → ожидается код 0, сообщение coverage ok
  2. Добавьте в requirements.md: '## REQ-999: Как админ, я хочу автоудаление инцидентов'
  3. Запустите скрипт снова → ожидается fail с сообщением: 'requirements.md:42: REQ-999 не имеет ссылки в plan.md. Добавьте в plan.md задачу с implements: REQ-999 или удалите требование.'
  4. Исправьте, добавив в plan.md задачу с implements: [REQ-999], или удалите REQ-999

Сложность: beginner

Название: Отрицательная фикстура и защита схемы

Проблема: В директории book2/examples/spec-ci запустите validate_schema.py. Затем создайте новую отрицательную фикстуру: valid-формат, но с severity: 'P0' и без backup_verified. Проверьте, что схема отклоняет её. Если проходит — схема слишком мягкая.

Решение: 1. python3 scripts/validate_schema.py --schema schemas/incident_payload.schema.json --fixtures fixtures → код 0, valid-incident.json: valid, invalid-missing-incident-id.json: expected invalid

  1. Создайте fixtures/invalid-p0-no-backup.json с _expected_invalid: true, incident_id: 'INC-003', severity: 'P0', но без backup_verified
  2. Запустите validate_schema.py снова
  3. Если получено 'invalid-p0-no-backup.json: expected invalid, rejected: missing required property backup_verified' → схема корректна
  4. Если проходит валидацию → модифицируйте схему: добавьте 'if severity == P0 then backup_verified required' и повторите

Сложность: intermediate

Название: Перенос Spec CI в capstone для high_memory_usage

Проблема: В capstone-проекте создайте строку Spec CI для сценария high_memory_usage. Требование: REQ-HM-01 «не перезапускать pod без подтверждённого RSS > 90% в течение 5 минут». Докажите связь с plan.md и создайте отрицательную фикстуру без incident_id.

Решение: 1. Убедитесь, что в requirements.md есть REQ-HM-01 с чётким условием (RSS > 90%, 5 минут)

  1. В plan.md добавьте задачу с implements: [REQ-HM-01]
  2. Запустите: python3 scripts/check_coverage.py --requirements requirements.md --plan plan.md → ожидается coverage ok
  3. Создайте фикстуру с high_memory_usage payload, но без incident_id, пометьте _expected_invalid: true
  4. Запустите validate_schema.py → ожидается rejected по missing required property incident_id
  5. Запишите в capstone/validation.md:

| Spec CI | check_coverage.py | REQ-HM-01 связано с plan.md | PASS | | Schema negative | validate_schema.py | missing incident_id заблокирован | PASS |

Сложность: intermediate

Название: Проверка области охвата: блокировка rogue-операции

Проблема: В учебном plan.md добавьте шаг 'TASK-ROGUE: автономное закрытие инцидента через POST /incidents/{id}/force-resolve без подтверждения оператора, с implements: [REQ-014]'. Проверьте, что scope-check блокирует эту операцию, хотя coverage остаётся зелёным.

Решение: 1. Добавьте TASK-ROGUE в plan.md с implements: [REQ-014] и endpoint POST /incidents/{id}/force-resolve

  1. Запустите check_coverage.py → зелёный (формальная связь есть)
  2. Запустите check_scope.py (или анализ вручную по доменной модели incident-response)
  3. Ожидается fail: 'plan.md:48 uses force_resolve without domain permission'
  4. Замените на POST /incidents/{id}/ack или добавьте отдельное требование и правило домена
  5. Повторите до зелёного статуса

Сложность: advanced

Название: Форматирование исправляемой диагностики

Проблема: Получите 'плохое' сообщение об ошибке: 'Coverage failed: missing REQ'. Преобразуйте его в 'хорошее' по четырём элементам: причина, файл/строка, идентификатор правила, действие. Запишите в JSON-формате.

Решение: Исходное (плохое): 'Coverage failed: missing REQ'

Преобразованное (хорошее): { 'status': 'failed', 'check': 'coverage', 'file': 'requirements.md', 'line': 42, 'rule': 'REQ-COV-014', 'reason': 'REQ-014 не имеет реализующей задачи в плане', 'action': 'Добавьте в plan.md задачу с implements: [REQ-014] или удалите требование из requirements.md' }

Проверка: сообщение позволяет исправить без открытия файлов и чтения логов процесса

Сложность: intermediate

Кейсы: Название: Инцидентный конвейер: как отрицательная фикстура предотвратила ложную эскалацию P0

Сценарий: Команда SRE в финтех-компании автоматизировала обработку алертов Grafana → PagerDuty. В validation.md содержались примеры вебхуков с полями incident_id, severity, source. Схема incident_payload.schema.json требовала backup_verified для severity: 'P0'. Спецификация была подключена к Spec CI с тремя слоями: coverage, scope, schema.

Задача: Разработчик 'оптимизировал' схему, убрав условие backup_verified для P0, считая, что 'всегда есть бэкап'. Через неделю другой разработчик добавил в plan.md шаг автоматического эскалации при P0 без изменения требований. Coverage остался зелёным (implements присутствовал), scope тоже (эскалация в домене). Но отрицательная фикстура invalid-p0-no-backup.json внезапно прошла валидацию — схема стала слишком мягкой.

Решение: Spec CI на уровне schema-check обнаружил, что отрицательная фикстура (помеченная _expected_invalid: true) прошла валидацию. Статус spec_gate стал красным, слияние заблокировано. Диагностика указала: 'validation.md:72 schema mismatch: negative fixture invalid-p0-no-backup.json passed, expected reject by missing backup_verified. Action: restore if-then requirement in incident_payload.schema.json: severity P0 requires backup_verified'. Команда восстановила строгость схемы и добавила явное требование REQ-BACKUP-01 в requirements.md.

Результат: Предотвращена ситуация, при которой инцидент с severity P0 без подтверждённого бэкапа автоматически эскалировал бы на дежурного в 3 часа ночи, хотя восстановление было невозможно. Время реакции на регрессию схемы: минуты вместо часов или дней. Команда зафиксировала правило: любое изменение схемы требует пары фикстур — валидной и отрицательной.

Извлечённые уроки: Отрицательные фикстуры — это регрессионные тесты для самой схемы; их прохождение — сигнал тревоги, а не успеха

Изменение схемы без изменения набора фикстур — классический антипаттерн, который Spec CI должен блокировать

Три слоя проверки (coverage, scope, schema) независимы: зелёный статус одного не компенсирует красный другого

Связанные концепции: schema-check

fixture

spec_gate

JSON-диагностика

Название: Rogue task и автономное закрытие: почему coverage недостаточен

Сценарий: В инцидентном проекте команда внедрила Spec CI с проверкой покрытия. Каждый REQ-* имел implements, каждая задача ссылалась на требование. На ревью это выглядело как идеальная трассировка.

Задача: Продукт-менеджер попросил 'ускорить' разрешение инцидентов. Разработчик добавил в plan.md задачу TASK-AUTO-RESOLVE с implements: [REQ-014] (общее требование 'дежурный получает подтверждение эскалации') и endpoint POST /incidents/{id}/force-resolve. Формально связь есть, но содержание — автономное закрытие без оператора — выходит за рамки доменной модели incident-response. Coverage-check прошёл зелёным.

Решение: Scope-check сработал на уровне доменной модели: действие force_resolve не входит в разрешённые операции (acknowledge, escalate, annotate, rollback, notify_on_call). Проверка учла не только глагол, но и актёра (автономный агент vs дежурный) и endpoint. Диагностика: 'plan.md:48: IR-SCOPE-007 — Autonomous force resolve is outside the incident-response domain model. Action: Replace with POST /incidents/{id}/ack or add an approved requirement and domain rule'.

Результат: Пулл-реквест заблокирован. Команда обсудила и отклонила автономное закрытие как рискованное. Вместо этого добавили явное требование REQ-MANUAL-ACK и задачу с человеческим подтверждением. Доменная модель осталась неизменной, доверие к ремедиации сохранено.

Извлечённые уроки: Граф покрытия по идентификаторам сильнее поиска по словам, но недостаточен без проверки содержания

Scope-check ловит semantic drift: когда формальная структура сохранена, а смысл изменён

Доменная модель — контракт между командой и системой; её нарушение опаснее отсутствия тестов

Связанные концепции: scope-check

coverage-check

rogue task

domain model

Советы по изучению: Начинайте с локального runnable-примера в book2/examples/spec-ci, не с GitHub Actions. Сначала добейтесь зелёного шлюза локально, затем переносите в CI

Используйте pre-commit hook только для изменённых файлов, полный прогон оставляйте для CI — это экономит время и делает шлюз привычной частью цикла

Практикуйтесь на 'плохих' диагностиках: берите сообщения вроде 'Coverage failed' и переписывайте в формат с файлом, строкой, правилом и действием

Создавайте отрицательные фикстуры параллельно с положительными — это защищает от 'мягких' регрессий схемы

Ведите 'дневник нарушений': записывайте, какие ошибки ловил spec_gate, и используйте для обучения команды

Для визуального стиля: нарисуйте на бумаге граф requirements → plan → domain → schema, отметьте, где какой gate срабатывает

Для аудиального стиля: объясните коллеге вслух, почему триггер push в main важен так же, как pull_request (прямое обновление служебных файлов)

Для кинестетического стиля: физически удалите строку implements из plan.md, запустите скрипт, почувствуйте блокировку, затем восстановите

Дополнительные ресурсы: Github spec kit: https://github.com/github/spec-kit — референсная реализация SDD-подхода, где требования, план и задачи становятся проверяемыми слоями

Runnable-примеры главы: book2/examples/spec-ci/scripts/check_coverage.py и validate_schema.py — локальный smoke-test без внешних зависимостей

Json schema validation: https://json-schema.org/understanding-json-schema/ — спецификация для создания строгих контрактов фикстур

Часть 9 первого тома: part-09-feature-validation.md — связь validation.md с фактами, база для понимания фикстур

Часть 16 первого тома: part-16-team-code-review.md — командное ревью пакета доказательств, контекст для автоматизации

Часть 12 первого тома: part-12-mvp.md — REQ-идентификаторы и схемы полезной нагрузки в учебном AgentClinic

Резюме: Шлюз спецификации (Spec CI) превращает requirements.md, plan.md, validation.md и API-контракты из справочной документации в исполняемые артефакты, блокирующие слияние. Три слоя проверки — coverage (граф REQ-* → implements), scope (соответствие доменной модели incident-response), schema (JSON-фикстуры с отрицательными примерами) — независимы и дополняют модульные тесты. Ключевой выигрыш: спор о спецификации сводится к диагностике с файлом, строкой, правилом и действием, снижая нагрузку на ревьюера. Для внедрения: сначала локальный runnable-пример, затем GitHub Actions с обязательным spec_gate в branch protection, всегда на push и pull_request. В инцидентной автоматизации такая строгость предотвращает ложные эскалации, опасные автооперации и потерю доверия к ремедиации.

Мои заметки
0 / 10000

Заметки сохраняются в этом браузере. На другом устройстве они не появятся.

Меню курса

Курс

Production SDD для Qwen Code CLI. Часть 2
Прогресс 0 / 100