Цикл 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 (см. Переменные
окружения). Чтобы добавить
репозиторий, поправьте карту в обоих местах пакета — их совпадение проверяет тест
пакетов.
Установка¶
- Включите в файл установки пакеты
selfdevиsdd(sddтребуетselfdev). - Задайте переменные установки: workspace, адреса репозиториев, ревьюер
(
SELFDEV_REVIEWER_PRINCIPAL— решает критерийreviewзадач на код). cp_packages apply: установщик опубликует типы задач, описания агентов (sdd-rules,selfdev-rules, исполнители) и правилоfeature-expand.- Заведите личность агента
sdd-rules— как у любого агента видаservice(bootstrap установки). Пока её нет, оценки правила —failed: credential_inactive. - Заведите задачу
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 |
| Зависимая задача не берётся | Предшественник ещё на приёмке (ревью или вливание) | Ожидаемо: решить ревью |
См. также¶
- Типы задач и статусы — приёмка типа.
- Правила вывода работы —
taskTypes, связи, личность правила. - Ревью и вливание кода
- Входы и выходы — документы цикла как артефакты.
- Агенты описанием —
agent:<key>. - Пакеты каталога