OpenSpec: Отклонённые предложения — конвенция о памяти решений
Нет состояния отклонения. Вот обходной путь.
Агент, который полгода назад предложил и внедрил «перенос персистентности в общую библиотеку», с удовольствием предложит то же самое в следующем квартале, если только что-то долговечное не сообщит ему, что эта идея уже была исследована и отклонена — а в OpenSpec сегодня нет встроенного состояния для этого.
/opsx:archive предназначен для одного исхода: изменения, которое было внедрено. Он синхронизирует дельта-спецификации в openspec/specs/ и перемещает папку в openspec/changes/archive/YYYY-MM-DD-<name>/ как запись о том, что изменилось и почему. Не существует противоположных команд /opsx:reject или /opsx:abandon, и в формате архива ничего не сообщает будущему предложению: «именно эта идея была исследована и отвергнута». Этот разрыв наиболее важен именно в тех кодовых базах, где OpenSpec в остальном хорошо подходит: brownfield-системах с небольшим числом контрибьюторов и агентов, которые периодически повторно исследуют одни и те же архитектурные вопросы — объединить эти два сервиса, поделить этот слой персистентности, заменить эту HTTP-границу прямым импортом.

Это не гипотетический разрыв. Он был поднят напрямую перед самими мейнтейнерами OpenSpec в виде запроса функции, и ход того обсуждения стоит знать, прежде чем импровизировать собственное исправление: к чему проект фактически пришел к выводу определяет, какие конвенции стоит принимать. Это руководство разбирает, что происходит, если полагаться только на /opsx:archive, реальное обсуждение, которое уже состоялось в трекере задач OpenSpec, и легкий паттерн decision.md, который можно принять сегодня, не ожидая — и не нуждаясь — в ядровой поддержке.
Почему только архивация не фиксирует отклоненное решение
Архивирование изменения, которое вы решили не строить, технически работает — папка уйдет из вашего активного списка в любом случае. Проблема в том, что этот архивный папка не в состоянии сообщить, оказавшись рядом с десятками внедренных изменений:
- Нет поля статуса. Архивное изменение выглядит идентично, внедрено оно или было брошено на третьем сообщении в
/opsx:propose. Коллега или агент, просматривающийopenspec/changes/archive/, не могут различить их, не открывая каждую папку предложения и не читая артефакты внутри. - Нет сигнала проверить в первую очередь. Ничто в рабочем процессе по умолчанию не указывает агенту искать в архиве перед составлением нового предложения.
/opsx:proposeсоставляется на основе вашего текущего запроса и состояния кодовой базы, и все – он не перекрестно ссылается на ранее отклоненные изменения, если вы не укажете ему это. - Дельта-спецификации, которые вы не хотите синхронизировать. Если отклоненное изменение уже имеет черновые дельта-спецификации и вы архивируете его обычным способом,
/opsx:archiveпредложит сначала синхронизировать эти дельты вopenspec/specs/. Принятие этого предложения заставит ваши канонические спецификации описывать поведение, которое вы решили не строить, что незаметно повреждает запись «что система делает сейчас», которую каждое другое предложение читает перед планированием.
Ни одно из этого не является багом. /opsx:archive делает ровно то, что сказано в его документации: завершает изменение, которое было внедрено. Случай отклонения намеренно находится за пределами этого задокументированного диапазона, и собственное руководство OpenSpec по командной работе явно указывает, что большая часть того, что они рекомендуют — конвенции веток, порядок ревью PR, когда архивировать — это конвенции, накладываемые поверх инструмента, а не то, что OpenSpec強制рует за вас. Обработка отклонения — это еще одна конвенция, которую вы можете определить самостоятельно, и CLI уже дает вам флаг, необходимый для этого: передайте --skip-specs при архивировании изменения, которое вы не внедряете, так что openspec archive investigate-shared-persistence --skip-specs уберет папку, не затрагивая openspec/specs/ вообще.
К чему фактически пришли мейнтейнеры OpenSpec по поддержке ADR
Прежде чем придумывать собственную домашнюю конвенцию, стоит прочитать, как этот точный вопрос разрешился публично, потому что решение более конкретное — и более интересное — чем просто «нет». GitHub issue #557 открыт в январе 2026 года с запросом первой-классной поддержки Architecture Decision Record (ADR): долговечные записи, которые сохраняются независимо от жизненного цикла какого-либо одиночного изменения, чтобы отклоненное или устаревшее решение оставалось видимым для всех будущих предложений. Контрибьютор даже открыл pull request с его реализацией.
Далее последовало семь месяцев по-настоящему содержательной дискуссии, в которой участвовали ведущий мейнтейнер Tabish Bidiwale (@TabishB) и несколько глубоко вовлеченных членов сообщества, охватывающих неизменяемые против изменяемых записей, принадлежит ли ADR фазе исследований или фазе дизайна, владение между изменениями, когда одно решение распространяется на десяток последующих изменений, и как ADR соотносятся с спецификациями как «авторитетное» описание системы. Раннее framing от Tabish Bidiwale задало направление, к которому тред в итоге пришел: OpenSpec должен оставаться легковесным по умолчанию и делать специализированные рабочие процессы, такие как ADR, настраиваемыми через систему схем, а не встраивать их в ядро. Член сообщества позже суммировал, к чему пришло обсуждение:
Рабочие процессы ADR ценны, но OpenSpec в настоящее время не имеет первой-классной/нативной поддержки ADR… направление, обсуждаемое здесь, заключается в том, чтобы сохранять рабочий процесс по умолчанию легковесным и делать специализированные рабочие процессы настраиваемыми.
Мейнтейнер Clay Good (@clay-good) закрыл issue на этой основе в августе 2026 года и переместил его в GitHub Discussion #1553, чтобы разговор мог продолжать развиваться, не оставаясь открытым как нерешенный баг. Это разумное решение для инструмента, чей весь питч заключается в избегании церемонии в стиле Spec Kit по умолчанию. Это также означает, что исправление находится на уровне выше, в одном из двух мест:
- Схема сообщества. Схема
spec-driven-with-adr, построенная техническим советником OpenSpec Hari Krishnan (@harikrishnan83) и задокументированная на intent-driven.dev, добавляет пятый артефакт в пайплайн по умолчанию из четырех артефактов OpenSpec. Она существует, потому что схема по умолчанию теряет рассуждения изdesign.mdв тот момент, когда изменение архивируется — только дельты спецификаций синхронизируются вперед, так что «почему» за решением исчезает вместе с изменением, если что-то другое не сохраняет его. - Конвенция на уровне репозитория. Небольшой, вручную написанный файл
decision.mdплюс правило именования, которое ничего не стоит принять и не требует установки кастомной схемы.
Остальная часть этого руководства подробно покрывает вариант два, поскольку он является точкой с наименьшим трением для большинства команд — и, как показывает раздел о схеме сообщества ниже, он совместим с переходом на этот более тяжелый инструмент позже, если ваш журнал отклонений вырастет настолько, чтобы заслужить это.
Конвенция decision.md для записи отклоненного изменения
Структурируйте отклоненное исследование так же, как и внедренное, но остановитесь перед синхронизацией каких-либо дельт и добавьте один файл, который прямо указывает на исход:
openspec/
changes/
archive/
2026-09-16-rejected-shared-persistence-layer/
proposal.md
decision.md
decision.md отвечает на те же четыре вопроса, на которые отвечает правильный Architecture Decision Record — что решено, почему, какие альтернативы существовали и что изменило бы ответ:
# Decision
Status: Rejected
## Decision
Не заменять межсервисную HTTP-границу прямым импортом пакетов
между двумя Go-сервисами.
## Reasons
- Увеличивает компиляционную связанность между независимо развертываемыми сервисами.
- Делает слой персистентности неявным, незадокументированным контрактом.
- Измеренная польза (задержка, дублирование кода) была меньше, чем
стоимость связанности в этой кодовой базе.
## Alternatives considered
- Общий внутренний Go-модуль -- отклонен по той же причине связанности.
- gRPC вместо HTTP -- отложено, не отклонено; пересмотреть, если
накладные расходы HTTP станут измеримой узкой точкой.
## Reconsider only if
- Два сервиса намеренно объединяются в один деплой, или
- Замеры задержки показывают, что HTTP-скачок является доказанной узкой точкой.
## Related
- Архитектурное правило: сервисы общаются через HTTP, а не общие пакеты.
Единственное жесткое правило, которое заставляет эту конвенцию работать: не выполняйте шаг синхронизации для отклоненного изменения. Если /opsx:propose уже набросал дельта-спецификации, прежде чем вы решили против изменения, используйте флаг, который CLI уже дает вам для этой ситуации:
openspec archive investigate-shared-persistence --skip-specs
--skip-specs говорит openspec archive убрать изменение, не затрагивая openspec/specs/ вообще, что является самым безопасным значением по умолчанию для всего, что вы архивируете без внедрения. Принятие обычного запроса на синхронизацию вместо этого объединит дельта-спецификации отклоненной идеи с вашими каноническими спецификациями, а канонический openspec/specs/ должен описывать то, что система делает сейчас, а не каждую идею, которая была набросана и отвергнута. Если изменение постоянно не дает изменений спецификаций по структурной причине — скажем, чисто исследовательская папка — OpenSpec также поддерживает объявление skip_specs: true в .openspec.yaml этого изменения, чтобы оно архивировалось чисто без флага каждый раз.
Именование отклоненных изменений, чтобы люди и агенты могли просматривать архив
Файл decision.md помогает только в том случае, если кто-то открывает папку. Префиксируйте имя папки исходом, чтобы и человек, просматривающий ls openspec/changes/archive/, и агент, перечисляющий изменения, могли определить статус, не открывая ни одного файла:
2026-09-16-rejected-shared-persistence-layer/
2026-09-20-abandoned-react-router-migration/
2026-10-01-superseded-old-auth-design/
2026-10-10-add-project-filtering/ # внедрено, префикс не нужен
Это отражает словарь статусов, уже рекомендуемый для самостоятельных записей решений — proposed, accepted, superseded, deprecated, — примененный к собственному архиву OpenSpec, а не к отдельной папке docs/decisions/. Держите словарь маленьким. Три или четыре согласованных префикса лучше, чем строка статуса свободного текста, которую каждое предложение пишет немного по-разному.
Как заставить вашего агента проверять архив перед новым предложением
Именование и файл decision.md решают обнаруживаемость для человека, просматривающего папку. Они сами по себе ничего не делают, чтобы агент искал в архиве перед составлением нового предложения — это должно быть явной инструкцией, потому что /opsx:propose не делает этого по умолчанию, и никакое количество аккуратного именования файлов не изменит этого само по себе.
Два места, куда поместить эту инструкцию, соответствующие тому, как OpenSpec уже ожидает внедрения проектно-специфичных руководств:
В openspec/config.yaml, под полем context:, которое внедряется в каждый запрос планирования (помните об ограничении 50KB, описанном в быстром старте OpenSpec):
context: |
Before proposing a change, search openspec/changes/archive for folders
prefixed "rejected-" or "abandoned-" that describe a materially similar
idea. If one exists, summarize its decision.md and state what has
changed before proposing the idea again. Do not re-litigate a rejected
decision without new evidence.
В AGENTS.md или собственных инструкциях агента вашего проекта, как постоянное правило, а не как blob контекста для каждого запроса:
## Rejected OpenSpec changes
When a proposal is investigated and rejected:
1. Do not sync or apply its delta specs.
2. Add `decision.md` with Status, Decision, Reasons, Alternatives
considered, and Reconsider only if.
3. Prefix the archived folder name: `rejected-<name>` or `abandoned-<name>`.
4. Before proposing a materially similar change, search
`openspec/changes/archive/` and reference the prior decision.
5. Do not reopen a rejected decision unless its documented
reconsideration conditions have actually changed.
Ни одна из инструкций не гарантирует соблюдение — агент все еще может пропустить шаг поиска, так же как он может пропустить чтение любого другого контекста, который вы внедряете. Но это разница между «информация существует где-то в репозитории» и «агенту говорят, каждый раз, идти искать ее», и только второе на самом деле снижает повторные исследования на практике.
Практический пример: отклонение предложения, а затем правильное его пересмотрение
Соберите детали вместе на конкретном случае. Скажем, коллега просит агента посмотреть на замену межсервисного HTTP-вызова прямым импортом Go-пакета, чтобы срезать сетевую задержку.
- Исследовать, затем предложить.
/opsx:exploreчитает оба сервиса, и/opsx:propose replace-http-with-direct-importнабрасывает предложение, документ дизайна, взвешивающий выигрыш в задержке против стоимости связанности, и черновой дельта-спецификацию. - Исследовать и отклонить. После проверки документа дизайна команда решает, что стоимость связанности — два независимо развертываемых сервиса, теперь делящих компиляционную зависимость — перевешивает выигрыш в задержке, который никто на самом деле не измерял как проблему. Ничего не строится.
- Архивировать без синхронизации. Вместо удаления папки, выполните
openspec archive replace-http-with-direct-import --skip-specs, затем добавьтеdecision.mdв архивную папку сStatus: Rejected, причинами выше и оговоркойReconsider only if, называющей условие, которое изменит ответ — например, «замеры задержки показывают, что HTTP-скачок является доказанной узкой точкой». Переименуйте папку с префиксомrejected-, чтобы она читалась какopenspec/changes/archive/2026-09-16-rejected-replace-http-with-direct-import/. - Через месяцы кто-то поднимает это снова. Другой контрибьютор, или тот же агент в новой сессии, получает запрос «ускорить вызов checkout-to-inventory» и начинает набрасывать предложение, которое выглядит очень похоже на ту же идею. Поскольку
openspec/config.yamlинструктирует агента искать в архиве в первую очередь, он находит отклоненную папку, читаетdecision.mdи сообщает обратно: «Материально похожее изменение было предложено и отклонено 2026-09-16 по причинам связанности. Условие пересмотра было «замеры задержки показывают, что HTTP-скачок является доказанной узкой точкой». У вас есть новые замеры, или это другая проблема?» - Команда предоставляет новые доказательства. Если профилирование теперь показывает, что HTTP-скачок действительно доминирует задержку checkout, это именно измененные обстоятельства, о которых просила исходная
decision.md. Агент продолжает с/opsx:propose, иdecision.mdнового предложения — когда и это также будет архивировано, принято или отклонено — ссылается на предыдущее подRelated, так что архив читается как непрерывная история решений, а не как две несвязанные папки, которые случайно описывают одну и ту же идею.
Пятый шаг — вся суть конвенции. Без него, шаг 4 либо вообще не происходит — агент просто повторно исследует с нуля — либо происходит по удаче, потому что человек помнил предыдущий разговор. Файл decision.md и инструкция поиска по архиву превращают «кто-то может помнить» в то, что рабочий процесс фактически проверяет.
Архив OpenSpec против выделенного журнала ADR: кто за что отвечает
Когда вы поддерживаете файлы decision.md внутри архива, имеет смысл явно указать, какой артефакт отвечает на какой вопрос, чтобы конвенция незаметно не превратилась в дублирующую документацию:
| Артефакт | Отвечает на вопрос |
|---|---|
openspec/specs/ |
Что система делает сейчас? |
openspec/changes/<name>/ (активное) |
Что мы предлагаем изменить прямо сейчас? |
openspec/changes/archive/<name>/ |
Что изменилось (или было отклонено) в прошлом и почему? |
docs/adr/ (самостоятельное, нейтральное к инструменту) |
Какое долговечное архитектурное правило мы выучили, независимо от какого-либо одиночного изменения? |
Для решения, достаточно узкого, чтобы принадлежать одному исследованию — «мы посмотрели на общий слой персистентности и сказали нет» — конвенция decision.md внутри архива выше достаточна. Для решения, которое должно пережить и ограничивать многие будущие изменения — «сервисы общаются через HTTP, никогда общими пакетами» — повысьте его до самостоятельного Architecture Decision Record в docs/adr/, и пусть decision.md отклоненного изменения ссылается на него под Related. Это разделение сохраняет архив OpenSpec сфокусированным на отдельных исследованиях, в то время как журнал ADR хранит небольшое количество правил, которые должны пережить жизненный цикл любого одиночного инструмента — включая будущее переезд от OpenSpec целиком.
Когда принять схему spec-driven-with-adr вместо
Описанная выше конвенция ручной сборки ничего не стоит и укладывается в пятнадцать минут настройки, что делает ее правильным значением по умолчанию. Но стоит понимать, что на самом деле делает более структурированная альтернатива, прежде чем решить, что вы переросли префикс именования.
spec-driven-with-adr вставляет пятый артефакт, adr, между design и tasks в пайплайне OpenSpec. Вместо прямого написания содержимого ADR в папку изменения, шаг adr производит краткий локальный для изменения манифест adr.md и, когда изменение вводит действительно долговечное архитектурное обязательство, пронумерованную запись в корне репозитория — /adr/0042-use-postgres-for-catalog.md, соседнюю с openspec/, а не вложенную в нее. Каждый ADR, создаваемый схемой, неизменяем после принятия: собственные инструкции схемы называют это «железным правилом» — вы никогда не редактируете статус, тело или дату принятой записи. Чтобы изменить предыдущее решение, вы пишете новый ADR, чье поле Supersedes: называет старый, и будущие дизайны проходят по этой цепи замены, чтобы знать, какие решения все еще в силе. Это более строгая версия именно идеи «пересмотреть только если» в конвенции decision.md выше,强制执行 схемой, а не оставленная на память человека.
Стоит быть точным в том, что эта схема решает, а что нет. Она построена для решений, которые принимаются и должны пережить архивирование — Postgres против DynamoDB, JWT против сессионных куки — а не для предложений, которые были исследованы и отклонены без внедрения чего-либо. Отклоненное исследование все еще не имеет очевидного места для жизни под этой схемой; вы наложите ту же конвенцию decision.md и именования из этого руководства поверх нее, просто ссылаясь на записи /adr/ вместо отдельной папки docs/adr/.
Дотянитесь до нее, когда заметите что-либо из этого:
- Ваш счетчик отклоненных решений достаточно велик, чтобы grep-поиск префиксов в
openspec/changes/archive/перестал быть быстрым. - Вы хотите, чтобы долговечные архитектурные решения валидировались и перекрестно ссылались на каждый новый дизайн автоматически, а не по конвенции и
grep. - Несколько контрибьюторов продолжают придумывать немного разные формы
decision.md, и вы хотите, чтобы схема принуждала к одному неизменяемому, пронумерованному формату.
Установка кастомной схемы — большее обязательство, чем конвенция именования — она меняет то, что генерирует /opsx:propose для каждого будущего изменения, а не только для отклоненных, — так что отнеситесь к ней как к шагу вверх, когда легковесная версия видимым образом напряжена, а не как к первому движению по умолчанию.
Заключение
Архив OpenSpec был спроектирован вокруг одного исхода — изменения, которое было внедрено — и его собственные мейнтейнеры были явны, после семимесячного публичного обсуждения, что первая-классная поддержка отклонения или ADR не скоро придет в основной рабочий процесс. Это оставляет исправление там, где OpenSpec уже помещает большинство своих командных конвенций: в вашем репозитории, а не в инструменте. Файл decision.md, флаг --skip-specs при архивировании, префикс именования rejected-/abandoned- и явная инструкция, говорящая агенту искать в архиве перед предложением, достаточно, чтобы остановить большинство повторных исследований. Дотянитесь до схемы spec-driven-with-adr только тогда, когда эта легковесная конвенция действительно напряжена количеством отслеживаемых вами решений — и даже тогда, сохраняйте четкое разграничение: она управляет решениями, которые вы приняли и хотите, чтобы они пережили архивирование, а не теми, которые вы отвергли.
Полезные ссылки
- Быстрый старт OpenSpec: установка, рабочий процесс и распространенные ловушки – установка, цикл explore-propose-apply-archive и повседневные ловушки
- Рабочий процесс Spec-Driven Development: от требований к коду – нейтральный к инструменту пятифазный процесс, в котором эта конвенция заполняет разрыв
- Записи решений для ИИ-ориентированной разработки ПО – общий формат ADR/PDR/DDR, жизненный цикл статусов и инструкции для чтения ИИ, которые эта конвенция заимствует
- GitHub issue #557: поддержка architecture decision records – полное семимесячное обсуждение того, почему ADR не являются ядром OpenSpec
- GitHub Discussion #1553 – где этот разговор продолжается после закрытия issue
- Схема spec-driven-with-adr – схема сообщества, которая сохраняет ADR живыми вне жизненного цикла изменения, от советника OpenSpec Hari Krishnan
- Документация командного рабочего процесса OpenSpec – как архивирование, ветки и ревью PR должны сочетаться
- GitHub Spec Kit vs Kiro vs Claude Code SDD Workflows – как OpenSpec сравнивается с более тяжелым SDD-инструментарием в целом