Спека как живой контракт: SPDD, archlint и двусторонний sync

Wei Zhang и Jessie Xia из Thoughtworks дали недостающую часть моего spec-driven workflow. Разбираю что взял и почему.

Симптом

LLM в кодовой базе ускоряет одного разработчика. Команда от этого не ускоряется — наоборот, на ревью обрушивается поток сгенерированного кода, который никто не успевает понять. Спека, написанная на старте задачи, через неделю уже не описывает то, что в master. Кто-то правит код, кто-то правит .md, через месяц расхождение замолчано.

Это не про дисциплину команды. Это про архитектуру процесса, в которой “спека” и “код” не имеют формальной связи.

Диагноз от Thoughtworks

28 апреля 2026 на сайте Мартина Фаулера вышла статья Structured Prompt-Driven Development от Wei Zhang и Jessie Xia. Они формулируют проблему точнее, чем я: “Local speed improves. But that doesn’t automatically translate into system-level throughput.”

Их предложение в трёх пунктах:

  1. Промпт — это first-class артефакт. Версионируется, ревьюется, переиспользуется как код. Не реплика в чате.
  2. REASONS Canvas — 7-частная структура промпта: Requirements, Entities, Approach, Structure, Operations, Norms, Safeguards. Первые четыре — абстракция, пятый — исполнение, последние два — governance.
  3. Замкнутая петля между промптом и кодом с правилом, что обновлять первым:
    • изменение поведения -> сначала промпт, потом код
    • рефакторинг -> сначала код, потом sync обратно в промпт

Третий пункт — главное. Он превращает вечный спор “что source of truth” в процедуру.

Где это совпало с моей практикой

У меня уже был свой spec-driven workflow:

  • ~/my/archlint/templates/specifications/spec-template.md — шаблон спеки с разделами Architecture, Requirements, Acceptance Criteria, Implementation Steps. Размерные градации XS/S/M/L/XL.
  • Правило в ~/.claude/rules/spec-workflow.md: “задача >30 минут или >3 шагов — обязательно спека до старта”.
  • Команда /ms-add-spec в Claude Code, которая генерирует спеку под задачу.
  • archlint — статический анализатор, который валидирует архитектурные правила (200+) на графе из AST.

REASONS Canvas почти один в один ложится на мой шаблон:

REASONSМой шаблон
R Requirements## Requirements (FR1, FR2, …)
E Entities## Architecture / Data Model (UML Class)
A Approach## Overview / Solution Summary
S Structure## Architecture / Component Overview (C4)
O Operations## Implementation Steps
N Norms(не было отдельного раздела)
S Safeguards(не было отдельного раздела)

Совпадение на 70-80%. Архитектурный governance у меня вообще сильнее — archlint проверяет автоматически то, что в SPDD держится на ревьюере-человеке.

Где SPDD добавил то, чего не было

Два пункта, которые у меня отсутствовали или были сформулированы неверно.

1. Спека “неизменна в процессе”

В моём spec-workflow.md буквально стояла формулировка:

Спека = ЧТО делать (неизменна в процессе)

Это противоположно идее живого артефакта. Спека написана, согласована, перенесена в inprogress/ — и потом никем не трогается, пока задача не закроется. На практике это значит, что любая правка реализации, отличающаяся от плана, проваливается между спекой и кодом.

2. Norms и Safeguards неявные

Стандарты команды (как именно мы оборачиваем ошибки, какой logger, какие naming-конвенции) у меня живут в куче .md файлов: ~/.claude/rules/architecture.md, проектные CLAUDE.md, в чате. На уровне отдельной спеки их явно никто не выносит. Авторы SPDD выделяют:

  • Norms — стандарты как принято писать. Часть автоматизирована (golangci-lint, archlint), часть нет.
  • Safeguards — неприкосновенные инварианты. Нарушение — стоп, не warning. Обратная совместимость, perf budgets, security boundaries.

Когда они в одной странице со спекой, тихий рефактор поперёк стандарта становится заметным на ревью.

Что я в итоге сделал

Два патча, оба сегодня.

Патч 1: ~/.claude/rules/spec-workflow.md

Удалил “Спека неизменна”. Заменил на “Спека — живой контракт, синхронизирован с кодом всегда”. Добавил раздел “Двусторонняя синхронизация” с явным правилом prompt-first vs code-first:

1
2
3
4
5
Изменение поведения (publicly-exposed контракт, бизнес-логика, валидация)
-> сначала спека, потом код

Рефакторинг (поведение не меняется)
-> сначала код, потом sync обратно в спеку

И отдельный раздел “Norms и Safeguards: governance внутри спеки” с примерами и привязкой к archlint/golangci-lint.

Патч 2: ~/my/archlint/templates/specifications/spec-template.md

Добавил две секции после Acceptance Criteria:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
## Norms

- N1: error wrapping через fmt.Errorf("%w") или errtrace.Wrap
- N2: логирование через slog с контекстом
- N3: naming - DB snake_case, JSON camelCase

Автоматизировано:
- [ ] golangci-lint passes (errcheck, errorlint, sloglint)
- [ ] archlint passes (layered, fan-out, ISP)

## Safeguards

- S1: обратная совместимость публичного API в рамках minor релиза
- S2: p99 latency endpoint X не растёт более чем на 10%
- S3: нет утечки PII в логи и метрики

Проверка:
- [ ] Smoke test на обратную совместимость
- [ ] Бенчмарк до/после
- [ ] Аудит логов на чувствительные поля

Размерные градации те же: для XS Safeguards обычно не нужны, для M/L/XL — обязательны.

Что я НЕ взял

Не взял CLI openspdd и команду /spdd-prompt-update. Слишком много церемонии для одиночной работы и для команды без отдельного workflow-инженера. У меня та же дисциплина держится на:

  • /ms-add-spec — создать спеку
  • /ms-checkpoint — зафиксировать прогресс на длинной задаче
  • archlint — валидация Norms+Safeguards автоматически где можно
  • Code review через GitLab — двусторонний sync проверяется на ревью

Не взял правило “никогда не редактировать промпт руками”. У них это compensation за CLI-managed lifecycle. У меня его нет, и руками править .md спеку — нормальная операция.

Не взял заявление про “~99% intent alignment”. Это маркетинг, кейс N=1.

Двойная оптика

Технический слой статьи: дисциплина для AI-кодинга в команде.

Архитектура мышления за этим: проблема, которую решают авторы — не “AI пишет неправильный код”, а “bandwidth ревьюера не растёт со скоростью генератора”. Когда LLM выдаёт результат быстрее, чем человек успевает его понять, узкое место — когнитивная пропускная способность того, кто принимает изменения. SPDD сжимает то, на чём держится ревью, до одного артефакта (Canvas), чтобы он влезал в bandwidth.

Это та же задача, про которую я говорил на Стачке — контроль сложности через граф. Только на уровне процесса, а не статического анализа.

archlint = governance внутри кода (граф, правила, инварианты). SPDD/спека = governance над изменениями (контракт между намерением и реализацией).

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

Когда есть оба — каждый коммит проходит и через “не сломал ли архитектуру” (archlint), и через “соответствует ли намерению” (спека). На ревьюера падает только то, что обе автоматизации пропустили.

Ссылки

Built with Hugo
Theme Stack designed by Jimmy