Agent Dev 101

Модуль 16 · Урок 16.18

Урок 16.18. Эволюция спецификаций и contract-driven development

На этой странице
  1. Зачем это нужно
  2. Основная идея
  3. Эволюция спек: циклы моделей
  4. Contract-Driven Development
  5. Практика
  6. Краткое резюме
  7. Вопросы для самопроверки
  8. Что дальше
  9. Источники

Зачем это нужно

Урок 16.8 ввел три модели хранения спецификаций как конвенции. Осталась практика: как именно поддерживать артефакты после внедрения (урок 16.17) - по какому циклу работает каждая модель и как не утонуть в ручном reconcil-е.

Вторая тема урока - контрактный подход: когда компоненты открывают интерфейсы друг другу, договориться об observable-обязательствах нужно до реализации каждой стороны. Спека фичи описывает поведение продукта, контракт - как компоненты сотрудничают для его доставки, план компонента - его внутреннее решение. Гайд CDD показывает, как это делается существующими командами Spec Kit и обычными версионируемыми артефактами - без автоматической синхронизации, cross-repo-резолвера зависимостей и релизной оркестрации.

Основная идея

Существующему проекту нужны два отдельных maintenance-цикла: обновление проектных файлов Spec Kit (managed-команды, скрипты, шаблоны, общие memory-файлы - апгрейд-воркфлоу урока 16.2) и эволюция артефактов фич (репозиторий-специфичные specs/, выровненные с кодом и поведением продукта). Для второго - по циклу на модель хранения. Для интерфейсов между компонентами - контракты с единственным авторитетным владельцем.

Эволюция спек: циклы моделей

Flow-forward: новая фича - новый каталог

Когда добавляется фича или существенное продолжение, создавайте новую спеку через установленный /speckit.specify и идите стандартным потоком:

  1. /speckit.specify - новый каталог фичи под specs/;
  2. /speckit.plan - подход к реализации;
  3. /speckit.tasks - разбивка работы;
  4. /speckit.implement - ревью код- и артефакт-diff вместе;
  5. /speckit.converge - полнота; при дописанных задачах повторять implement/converge до полного завершения.

Прежний каталог фичи остается нетронутым - для аудита, сравнения, объяснения текущего состояния проекта. Используйте ясные имена фич и кросс-ссылки, когда новый каталог сменяет или расширяет раннюю работу.

Living spec: спека - контракт

Когда намеренное поведение меняется, сначала ревизуйте существующий spec.md, затем регенерируйте или вручную правьте производные артефакты:

  1. Начните с чистого рабочего дерева или выделенной ветки - каждая генерация reviewable;
  2. Обновите spec.md через /speckit.clarify или явной правкой;
  3. Перезапустите /speckit.plan или отревизуйте plan.md под новую спеку;
  4. Перезапустите /speckit.tasks или отревизуйте tasks.md под новый план;
  5. /speckit.analyze до возобновления реализации - поймать пробелы между спекой, планом и задачами;
  6. /speckit.implement, ревью кода и артефактов вместе;
  7. /speckit.converge; при дописанных задачах - цикл до завершения.

Сохраняйте важную обоснованность реализации до замены производных артефактов: если план или список задач содержат решения, которые все еще важны, переносите их явно.

Flow-back: правки оттуда, где всплыло открытие

Первый полезный edit происходит там, где landed находка: spec.md, plan.md, tasks.md или реализация. После изменения приведите набор в соответствие:

  1. Зафиксируйте открытие в ближайшем к работе артефакте;
  2. Решите, меняет ли оно намеренное поведение, стратегию реализации, разбивку задач или только код;
  3. Обновите остальные артефакты, разошедшиеся с принятым направлением;
  4. /speckit.analyze - проверить пробелы между spec.md, plan.md, tasks.md;
  5. Продолжайте реализацию только после того, как набор описывает поведение и подход, которым будущие контрибьюторы смогут доверять.

Flow-back гибок, но требует дисциплины: не оставляйте нижележащее изменение в tasks.md или коде, если spec.md говорит другое и спека должна оставаться заслуживающей доверия.

До обновления проектных файлов

Перед refresh-ом файлов проекта через specify init --here --force --integration <your-agent> защищайте проект-специфический материал вне specs/ - особенно .specify/memory/constitution.md и кастомизированные файлы в .specify/templates/ и .specify/scripts/. Каталог specs/ не входит в template-пакет, но общие файлы проекта форсированный refresh может перезаписать.

Contract-Driven Development

Когда компонент открывает интерфейс внешнему потребителю, определите контракт, на который потребитель может полагаться. Контрактный подход: договориться о контракте, реализовать каждую сторону против него и проверить, что обе стороны выполняют обязательства.

Место внутри SDD: продуктовые требования фиксируют намеренное поведение; контракты определяют, как компоненты сотрудничают для его доставки; план реализации каждого компонента описывает внутреннее решение. Определяйте границу взаимодействия первой, вместо того чтобы считать границей репозиториев дизайн.

Когда нужен контракт

«Внешний» - за пределами границы реализации компонента, не обязательно за пределами процесса, репозитория или организации. Примеры: сайт зовет backend API; сервис зовет другой или потребляет его события; приложение использует библиотеку или интерфейс плагина; автоматизация вызывает CLI и парсит вывод; компоненты обмениваются файлами в согласованном формате.

Принцип применим к монолитам, модульным приложениям, микросервисам и прочим архитектурам - раскладка репозиториев не определяет, нужен ли контракт. Форма и детальность должны соответствовать интерфейсу: маленькой библиотеке хватит документированных сигнатур и поведения; публичному HTTP API - OpenAPI-схемы и исполняемых примеров. Не каждому контракту нужны отдельная схема или реестр.

Что определяет контракт

Observable-обязательства, позволяющие реализовать каждую сторону, не завися от внутренностей другой:

  • принимаемые входы и производимые выходы, включая форматы и правила валидации;
  • поведение и побочные эффекты, включая ошибочные случаи;
  • релевантные гарантии взаимодействия: идемпотентность, порядок событий, ретраи, таймауты;
  • ожидания совместимости, версионирование и политика деприкации;
  • примеры и критерии верификации для провайдеров и потребителей.

Схема alone может не покрыть весь договор: форма order-запроса не объясняет, может ли ретрай создать второй заказ. Документируйте и семантику. Не экспонируйте внутренние структуры БД и детали реализации, если они не часть публичного интерфейса.

Один авторитетный владелец

Одна сторона владеет авторитетным контрактом; другая потребляет его. Обычно владелец - компонент, открывающий интерфейс. Делайте владение явным для каждого интерфейса; затронутые потребители участвуют в согласовании изменений - владение не означает односторонних правок.

Ситуация Как делиться контрактом
Обе стороны в одном репозитории ссылаться на один авторитетный файл/артефакт вместо раздельных определений; независимо релизящиеся компоненты все равно фиксируют поддерживаемую версию контракта
Стороны в разных репозиториях публиковать версионируемый артефакт/пакет для пиновки потребителями или синхронизировать копию в каждый потребляющий репозиторий
Потребитель держит синхронизированную копию записать авторитетный источник и точную версию/коммит; копия - read-only input; изменения предлагаются в источнике

Для вендоренной копии соседний README фиксирует репозиторий-источник, путь, неизменяемую ревизию или digest релизного артефакта и процедуру обновления; пакетная зависимость записывает эквивалент в lockfile. Потребителям нужен авторизованный доступ к артефакту контракта - доступ к репозиторию реализации провайдера не обязателен.

Обновления - осознанные: согласовать изменение в авторитетном источнике, опубликовать версию, затем ревьюить обновление версии/копии у каждого потребителя. Не синхронизируйте всех молча на «latest». Запинованный контракт идентифицирует договор, но не гарантирует, что деплойнутый провайдер его все еще поддерживает.

Workflow Spec Kit для контрактов

  1. Зафиксировать намерение и найти интерфейсы. /speckit.specify фиксирует пользовательское поведение; определите, какие компоненты предоставляют и потребляют каждое взаимодействие. Если контракта нет - его определение часть работы, а не пререквизит, который должен был быть где-то готов.
  2. Договориться до зависимой реализации. В /speckit.plan владелец драфтит контракт и ревьюит с потребителями; вопросы observable-поведения и совместимости решаются до того, как любая сторона реализует предположения о другой. Дальше стороны развиваются независимо против согласованной версии.
  3. Доставить договор каждому затронутому проекту. Дайте агенту точную версию и доступное содержимое контракта плюс релевантные требования. Не предполагайте, что ссылка открывает файлы чужого репозитория. Каждый проект владеет локальными spec.md/plan.md/tasks.md; ссылайтесь на контракт, не копируйте чужой план.
  4. Спланировать верификацию явно. Попросите /speckit.tasks включить контрактные тесты провайдера и потребителя, включая негативные случаи. Тестируйте observable-поведение, не только формы данных. Тесты потребителя по мокам полезны, но не доказывают конформность реального провайдера - включайте верификацию провайдера и интеграционную валидацию.
  5. Реализовать и валидировать каждую сторону. /speckit.implement в каждом проекте, затем согласованные проверки. Если реализация вскрыла проблему контракта - ревизуйте авторитетный договор и reconcil-ьте затронутые спеки, планы, тесты и версии потребителей, а не правьте копию приватно.
  6. Релизить совместимые реализации. Отслеживайте, какие деплойнутые версии компонентов поддерживают какие версии контрактов; последовательность rollout и rollback - вокруг этих зависимостей. Для ломающих изменений - договоритесь о миграции и периоде перекрытия до удаления поведения, которое потребители еще используют.

/speckit.plan уже производит feature-scoped артефакты contracts/ при внешних интерфейсах. Явно выберите авторитетный артефакт: фича может драфтить новый контракт там или предлагать изменение установленного контракта в другом месте проекта; зафиксируйте одобренный источник и версию в артефактах фичи. Исторические снапшоты и синхронизированные копии - не дополнительные редактируемые источники правды; Spec Kit не публикует и не синхронизирует их автоматически.

Разобранный пример: чекаут сайта через сервисы

Гипотетический чекаут: сайт, сервис заказов и сервис инвентаря, каждый в своем репозитории, контрактов нет. Требование: клиент может оформить заказ, только если все позиции резервируются, а ретрай запроса не должен создавать дубль заказа или резерва.

Сначала - идентифицировать и согласовать два контракта (сводки; авторитетные артефакты обязаны определить и детали входов/выходов):

Контракт Владелец/провайдер Потребитель Observable-договор
Orders API Сервис заказов Сайт принимает order-запрос с ключом идемпотентности; возвращает заказ или определенную ошибку; ретраи не создают дублей
Inventory API Сервис инвентаря Сервис заказов резервирует все позиции или репортит нехватку без частичного резерва; ретраи не создают дублей

Сервис заказов - провайдер одного интерфейса и потребитель другого: он владеет контрактом Orders API, не Inventory API.

Раскладка на синхронизированных копиях:

text
inventory-repo/
  .specify/
  contracts/inventory-api.yaml     # авторитетный контракт Inventory API
  specs/001-reserve-inventory/

orders-repo/
  .specify/
  contracts/orders-api.yaml        # авторитетный контракт Orders API
  contracts/inventory-api.yaml     # read-only копия, пин Inventory API 1.0.0
  contracts/README.md              # ревизия источника и процедура синхронизации
  specs/001-place-order/

website-repo/
  .specify/
  contracts/orders-api.yaml        # read-only копия, пин Orders API 1.0.0
  contracts/README.md
  specs/001-checkout/

Имена и версии иллюстративны, не обязательная раскладка. Каждый проект инициализирован независимо и ведет обычный SDD-цикл:

  1. Команда инвентаря согласует Inventory API 1.0.0 с командой заказов; команда заказов - Orders API 1.0.0 с сайтом. Каждый владелец публикует одобренный контракт, потребители пинят копии.
  2. Каждая команда специфицирует и планирует свою часть чекаута против договоров: сайт - взаимодействие клиента, заказы - размещение заказа, инвентарь - резервирование. План заказов учитывает оба контракта и сбои между резервом и созданием заказа.
  3. Свяжите локальные спеки с одним issue/roadmap-вхождением продуктового сценария; зафиксируйте версии контрактов и связанные спеки/PR сторон. Локальные номера фич и ветки совпадать не обязаны - это трассируемость, не общий план реализации.
  4. Реализуйте и проверьте оба интерфейса, включая ретраи, нехватку и сбои; валидируйте полный путь чекаута и обязательства каждого компонента.
  5. Для начального rollout: сделать реализацию инвентаря доступной до включения зависимой реализации заказов, затем включить чекаут сайта. Зафиксируйте деплойнутые версии и ограничения rollback - публикация контракта alone не делает реализацию доступной.

Если Orders API 1.1.0 позже добавляет опциональную заметку о доставке: предложите изменение в orders-repo, проверьте совместимость с потребителями, затем сайт осознанно принимает новую версию. Не редактируйте синхронизированную копию сайта, изобретая поддержку, которой сервис заказов не согласовал.

Тот же дизайн работает и в одном репозитории на три компонента: ссылайтесь на авторитетные контракты напрямую вместо синхронизации копий (раскладка и таргетинг - урок 16.17). Контракт соединяет реализации; раскладка репозиториев меняет только способ шаринга договора.

Пример: control plane, data plane и интеграционные тесты

Три репозитория: control plane (r1) управляет конфигурацией, data plane (r2) применяет ее в трафике, интеграционные тесты (r3) проверяют взаимодействие. Это то же применение принципа, не требование так организовывать системы.

Определить взаимодействие первым - если контракта еще нет, договоритесь об observable-поведении до реализации предположений:

Аспект контракта Пример договора
Входы ревизия конфигурации и payload с явными правилами валидации
Выходы acknowledgement с ревизией и статусом (принято/применено); как наблюдать завершение при асинхронности
Ошибки определенные ответы для невалидной конфигурации и устаревшей ревизии; прежняя валидная конфигурация остается активной
Поведение ретрай той же ревизии и payload не применяет ее дважды; переиспользование ревизии с другим payload отвергается
Совместимость идентификация поддерживаемых версий контракта; сохранение поведения, на которое опираются текущие вызовы, на время миграции

Здесь r2 открывает интерфейс и владеет авторитетным контрактом; r1 участвует в согласовании и потребляет пинованную версию; r3 использует ту же версию для верификации взаимодействия - включая невалидный ввод, ретраи и совместимость. Тесты - подтверждения договора, не конкурирующее его определение. Каждый проект держит собственный план; ссылайтесь на общий продуктовый интент и версию контракта без зонтичного репозитория, совпадающих имен веток и атомарных коммитов.

Эволюция согласованного контракта (rollout-последовательность, адаптирующая гайдлайн контрибуции TongyiDai) - пусть согласовано добавление опционального поля конфигурации:

  1. Опубликовать совместимое изменение. Обновить авторитетный контракт в r2, дать явную версию, опубликовать схему и fixtures совместимости; проверить, что отсутствие поля сохраняет прежнее поведение.
  2. Деплой поддержки до включения использования. Если r1 нужно новое поведение r2 - задеплоить r2 в режиме поддержки старых и новых потребителей, только потом включать зависимое поведение в r1. Порядок следует зависимости интерфейса, не именам репозиториев или порядку мержа PR.
  3. Готовить version-aware интеграционные тесты. Добавить покрытие в r3 заранее; выбирать ожидания по поддерживаемой версии контракта или явной capability, не по имени ветки. Существующие проверки совместимости держать обязательными; новый end-to-end гейт сделать обязательным до включения фичи и не пропускать молча после активации.
  4. Трекать готовность неизменяемыми ссылками. Issue/roadmap связывает одобренный контракт, релизы провайдера и потребителей, end-to-end результаты и критерии удаления старого пути с точными коммитами или релизными артефактами; различать смерженное и деплойнутое-готовое.
  5. Сохранить путь отката. Для provider-first rollout: отключить/откатить новое поведение потребителя раньше отката провайдера; проверить совместимость персистентного состояния и конфигурации - смена порядка деплоя alone не отменяет изменения данных. Старый контракт удалять только поздней очисткой, убедившись, что поддерживаемые потребители больше не зависят от него.

Если ломающее изменение неизбежно: расширить поддержку для миграции, осознанно перевести потребителей и только потом retir-ить старое поведение. Версионированный контракт и запись готовности не превращают отдельные деплои в транзакцию: это командные договоры и проверки, а не новый резолвер зависимостей или релизный оркестратор Spec Kit.

Практика

  1. Проведите одну реальную итерацию living-модели: измените требование в spec.md своего проекта, регенерируйте план и задачи, прогоните /speckit.analyze и добейтесь чистого отчета.
  2. Смоделируйте flow-back: внесите «находку реализации» прямо в tasks.md, затем по циклу поднимите ее до spec.md и убедитесь, что /speckit.analyze не видит рассогласования.
  3. Для любого своего межкомпонентного интерфейса составьте таблицу «аспект-договор» по образцу примера урока и определите авторитетного владельца; проверьте, покрыта ли семантика ретраев и идемпотентности.

Краткое резюме

Эволюция спек - два отдельных цикла: обновление проектных файлов Spec Kit и эволюция артефактов фич по выбранной модели (flow-forward - новая фича в новый каталог; living - спека первой, производные регенерируются, analyze перед реализацией; flow-back - правка там, где открытие, затем дисциплинированный reconcil). Контрактный подход: observable-договор до реализации сторон, один авторитетный владелец интерфейса, пинованные версии у потребителей, верификация провайдера и потребителя в задачах, осознанная эволюция с provider-first порядком и сохранением пути отката.

Главное из урока:

  • до init --here --force защищайте конституцию и кастомизации - общие файлы могут перезаписаться, specs/ не входит в шаблоны;
  • схема не заменяет семантику: идемпотентность, ретраи и порядок событий - часть контракта;
  • копия контракта у потребителя - read-only; изменения предлагаются в источнике;
  • тесты потребителя по мокам не доказывают конформность провайдера;
  • publication контракта != доступность реализации: трекайте деплойнутые версии и порядок rollout/rollback.

Вопросы для самопроверки

  1. Назовите два отдельных maintenance-цикла существующего проекта. Какими командами идет каждый?
  2. Опишите цикл living-модели: с чего начинается изменение и где стоит /speckit.analyze?
  3. В чем главный риск flow-back и какая дисциплина его сдерживает?
  4. Что означает «внешний потребитель» в CDD? Почему раскладка репозиториев не определяет необходимость контракта?
  5. Как распределяется владение контрактом? Какие три способа шаринга описаны и когда каждый уместен?
  6. Опишите порядок provider-first rollout при добавлении опционального поля. Почему откат потребителя предшествует откату провайдера?

Что дальше

Инструментальные темы исчерпаны. Урок 16.19 - экосистема сообщества: как публиковать и находить расширения, пресеты, бандлы и walkthroughs, и что такое friends-проекты.

Источники

Обновлено 03.10.2026