Перейти к содержанию

Цикл spec-driven разработки

Пакет каталога sdd описывает разработку фичи как цепочку типов задач: дизайн (spec и plan) с одними воротами, разбиение на задачи по строгой форме и сходимость ветки фичи в основную ветку каждого репозитория. Всё поведение цикла — данные пакета: типы задач, критерии приёмки, исходы approval и правило, которое заводит задачи по документу задач. Статья для администраторов установки и руководителей разработки. Обоснование — TAI-ADR-0047 и TAI-ADR-0053.

Шаги цикла

flowchart TB
    D["feature-design<br/>spec + plan"] -- "ворота: approve<br/>+ feature.design_check@1" --> T["feature-tasks<br/>документ задач"]
    D -- reject --> D
    T -- "сдача → критерий form<br/>tasks.check@1" --> V{"форма верна?"}
    V -- нет --> T
    V -- да --> C["task.completed"]
    C --> R["правило feature-expand<br/>(личность sdd-rules)"]
    R --> K1["coding-task × N<br/>depends_on по документу"]
    R --> K2["feature-converge<br/>по репозиторию"]
    K1 -- "review → merge<br/>в ветку фичи" --> K2
    K2 -- "ворота: approve<br/>git.merge@1" --> M["ветка фичи влита<br/>в основную ветку"]
Шаг Тип задачи Кто исполняет Результат Чем принят
Дизайн feature-design человек со своим харнессом spec.md и plan.md в specs/<featureSlug>/ на ветке фичи, выходы spec и plan Gate-approval: approve вызывает feature.design_check@1, при ok заводит feature-tasks и закрывает дизайн; reject — назад в in_progress
Разбиение feature-tasks исполнитель, назначенный исходом дизайна (исполнитель дизайна) tasks.md на ветке фичи, выходы tasks и spec Критерий типа form: tasks.check@1 вернул ok
Исполнение coding-task агент из строки «Исполнитель» или исполнитель шага разбиения Коммит на ветке задачи, влитый в ветку фичи Критерии типа review и merge (см. Приёмка типа)
Сходимость feature-converge исполнитель шага разбиения Ветка фичи влита в основную ветку репозитория Gate-approval: approve вливает коммит commit скиллом git.merge@1

Задачи исполнения и сходимости заводит правило, а не человек и не исполнитель шага разбиения.

Документ задач

Документ задач — specs/<featureSlug>/tasks.md, форма закреплена шаблоном specs/_templates/tasks.md суперпроекта. Проверяет её детерминированный скилл tasks.check@1 — один и тот же разбор и для приёмки шага, и для правила, которое заводит задачи.

# Tasks: <название фичи>

- Фича: `<slug>`, spec: [spec.md](spec.md), plan: [plan.md](plan.md)

## Фаза 1. Контракты

### X001 — Контракт API

- Репозиторий: service-a
- Исполнитель: agent:coder
- Зависит от: —
- Требования: FR-001, SC-001.
- Сделать: схемы запроса и ответа в OpenAPI.
- Приёмка: contract-тест зелёный.

## Фаза 2. Реализация

### X002 — Реализация [P]

- Репозиторий: service-a
- Исполнитель: agent:coder
- Зависит от: X001
- Требования: FR-002.
- Сделать: обработчик и миграция.
- Приёмка: тесты на SQLite и Postgres.

### X003 — Руководство

- Репозиторий: суперпроект
- Исполнитель: человек
- Зависит от: X002
- Требования: FR-003.
- Сделать: страница руководства.
- Приёмка: сборка документации без ошибок.

## Покрытие

| Требование | Задачи |
|---|---|
| FR-001 | X001 |
| FR-002 | X002 |
| FR-003 | X003 |
| SC-001 | X001 |

Правила формы

  • Пункт — заголовок ### <ID> — <название>, ID вида [A-Z]+\d{3}, уникален в документе; [P] в конце заголовка — можно делать параллельно с соседями по фазе.
  • У каждого пункта обязательны строки - Репозиторий:, - Исполнитель:, - Зависит от:, - Требования:, - Сделать:, - Приёмка:; повтор строки или пустое значение — ошибка.
  • Репозиторий — ровно один, имя из карты репозиториев установки (см. ниже); пункт на два репозитория — ошибка формы.
  • Исполнитель — agent:<key> (описание агента в пакете) или человек. Идентификаторы principal'ов в документе не пишутся.
  • Зависит от — ID пунктов этого документа через запятую или «—». Ссылка на несуществующий пункт и цикл — ошибки формы.
  • Требования — FR-### и SC-### из spec; строка — для человека.
  • Раздел ## Покрытие — таблица «требование → задачи»: каждое FR и SC из spec покрыто хотя бы одним пунктом, в таблице нет неизвестных пунктов и требований.
  • Не больше 50 пунктов вместе с задачами сходимости — столько правило разворачивает за одну оценку.
  • Задачи сходимости в документ не пишутся: их заводит правило.

Что скилл не проверяет: существует ли агент agent:<key> (это проверит ядро при заведении задачи, 422 unknown_agent), верность разбиения и размер пунктов — это решает человек на воротах дизайна.

Скилл tasks.check@1

Вход Смысл
repository, ref, slug Откуда читать specs/<slug>/tasks.md и spec.md — клон репозитория на ветке фичи
document, spec Текст документа и spec целиком — для отладки вместо клона
repositories Карта «имя в документе → {url, branch}»
humanAssignee Кому назначать пункты «человек» и задачи сходимости

Выход: status (ok или gaps), gaps — список {kind, line, detail}, text — сводка для комментария, items — задачи для правила, stats.

Скилл читает документ из git, а не из артефакта: tasks.md коммитится в ветку фичи рядом со spec и plan и публикуется до сдачи шага. Выход tasks (артефакт tasks-document) сдаётся дополнительно — его получает входом сходимость.

Виды ошибок формы (gaps[].kind): bad_heading, bad_id, duplicate_id, missing_field, empty_field, duplicate_field, multiple_repositories, unknown_repository, bad_assignee, bad_dependency, unknown_dependency, dependency_cycle, too_many_items, no_items, slug_mismatch, missing_coverage, bad_coverage_row, coverage_unknown_item, uncovered_requirement, unknown_requirement.

Приёмка шага разбиения

Тип feature-tasks объявляет критерий по умолчанию form — deterministic со скиллом tasks.check@1 и expect: {status: ok}. Документ с ошибкой формы не даёт шагу завершиться: попытка проверки проваливается, причина из gaps приходит комментарием, задача возвращается исполнителю, и демон исполнителя передаёт её в следующий прогон блоком «Замечания последней проверки» (см. Возврат исполнителю). Исправленный документ сдаётся снова.

Правило feature-expand

Когда шаг разбиения завершён (событие task.completed задачи типа feature-tasks), правило feature-expand пакета sdd разбирает тот же документ тем же скиллом и заводит задачи:

apiVersion: taimen.ai/v1
kind: WorkRule
key: feature-expand
spec:
  workspaceId: ${SELFDEV_WORKSPACE_ID}
  identity: {agent: sdd-rules}
  trigger: {kind: event, type: task.completed}
  condition: {eq: [{var: task.typeKey}, feature-tasks]}
  interpretation:
    skill: tasks.check@1
    inputs:
      repository: "{{task.customFields.repository}}"
      ref: "{{task.customFields.branch}}"
      slug: "{{task.customFields.featureSlug}}"
      humanAssignee: "{{task.assigneeId}}"
      repositories: { … }       # та же карта, что у критерия form
  action:
    kind: ensure_work
    forEach: skill.output.items
    taskType: "{{item.type}}"
    taskTypes: [coding-task, feature-converge]
    dedupKeyTemplate: "{{item.dedupKey}}"
    fields:
      title: "{{item.title}}"
      description: "{{item.description}}"
      priority: "{{task.priority}}"
      assignee: "{{item.assignee}}"
      customFields:
        baseBranch: "{{item.customFields.baseBranch}}"
        featureSlug: "{{item.customFields.featureSlug}}"
        repository: "{{item.customFields.repository}}"
        branch: "{{item.customFields.branch}}"
        targetBranch: "{{item.customFields.targetBranch}}"
      relations:
        spawnedBy: "{{task.id}}"
        dependsOn: "{{item.dependsOn}}"

Что получается:

Элемент Тип Исполнитель Поля Связи
Пункт документа coding-task agent:<key> из строки «Исполнитель»; для «человек» — исполнитель шага разбиения (humanAssignee) baseBranch: feature/<slug> — ветка задачи отводится от ветки фичи и вливается в неё spawned_by → шаг разбиения; depends_on → пункты из «Зависит от»
Сходимость (одна на каждый упомянутый репозиторий, после всех его пунктов) feature-converge исполнитель шага разбиения featureSlug, repository (URL из карты), branch: feature/<slug>, targetBranch (основная ветка из карты) spawned_by → шаг разбиения; depends_on → все пункты этого репозитория
  • Ключ дедупликации — feature:<slug>:<ID пункта>, у сходимости — feature:<slug>:converge:<репозиторий>. На те же ключи ссылается dependsOn, поэтому связи разрешаются внутри одной оценки, а повторная оценка (второе task.completed) не дублирует ни задач, ни связей.
  • Пункты идут в порядке зависимостей, сходимости — последними.
  • Исполнитель agent:<key> ядро разрешает в principal агента; неизвестный или не связанный агент — ошибка действия unknown_agent (см. Правила вывода работы).
  • Автор заведённых задач и события work.derived — агент sdd-rules (identity), а не человек, применивший пакет. Его права — events.read, tasks.read, tasks.write, skills.invoke.
  • Зависимая coding-task не выдаётся исполнителю, пока предшественник не принят — ревью одобрено и ветка влита в ветку фичи: приёмка типа держит предшественника невыполненным до вливания.

Сходимость получает spec и документ задач входами от шага разбиения (spawned_by) и вливает ветку фичи в основную ветку своего репозитория по решению на воротах.

Карта репозиториев

Имена репозиториев в документе — ключи карты repositories, одинаковой во входах критерия form типа feature-tasks и правила feature-expand. Адреса — топология установки, поэтому в пакете это переменные:

Имя в документе Переменная установки Основная ветка
суперпроект SELFDEV_SUPERPROJECT_URL main
control-plane SELFDEV_CONTROL_PLANE_URL main
memory-service SELFDEV_MEMORY_SERVICE_URL master
iam-service SELFDEV_IAM_SERVICE_URL main
notification-service SELFDEV_NOTIFICATION_SERVICE_URL main

Правило и тип задач пишут задачи в workspace SELFDEV_WORKSPACE_ID. Все переменные задаются в .env установки до cp_packages apply (см. Переменные окружения). Чтобы добавить репозиторий, поправьте карту в обоих местах пакета — их совпадение проверяет тест пакетов.

Установка

  1. Включите в файл установки пакеты selfdev и sdd (sdd требует selfdev).
  2. Задайте переменные установки: workspace, адреса репозиториев, ревьюер (SELFDEV_REVIEWER_PRINCIPAL — решает критерий review задач на код).
  3. cp_packages apply: установщик опубликует типы задач, описания агентов (sdd-rules, selfdev-rules, исполнители) и правило feature-expand.
  4. Заведите личность агента sdd-rules — как у любого агента вида service (bootstrap установки). Пока её нет, оценки правила — failed: credential_inactive.
  5. Заведите задачу feature-design с полями featureSlug, repository, branch и назначьте её человеку.

Типичные проблемы

Симптом Причина Что делать
Шаг разбиения возвращается в работу с комментарием gaps Документ не прошёл tasks.check@1 Исправить документ по списку ошибок и сдать снова
unknown_repository Имя репозитория в пункте не из карты установки Поправить документ или карту repositories пакета
После завершения шага задач нет Оценка правила failed (credential_inactive, work_items_refused) GET /rules/{id}/evaluations?status=failed; завести личность sdd-rules, проверить work[].refused
Часть пунктов не заведена, в оценке refused: unknown_agent В документе агент, которого нет в реестре или который не связан Применить описание агента и дождаться его личности, затем повторить оценку новым task.completed
Зависимая задача не берётся Предшественник ещё на приёмке (ревью или вливание) Ожидаемо: решить ревью

См. также