OpenSpec 却下提案:決定メモリ規約

拒否状態がありません。以下はその回避策です。

目次

6か月前に「永続化レイヤーを共有ライブラリに移行する」ことを提案し、リリースまでこぎつけたエージェントは、何らかの永続的な記録がそのアイデアが既に調査され、却下されたことを示さない限り、来四半期にも快く同じ提案をするだろう——そしてOpenSpecには、現在そのための内蔵状態管理は存在しない。

/opsx:archive は一つの成果物、すなわち「リリースされた変更」のために作られている。これはデルタ仕様(差分仕様)を openspec/specs/ に同期し、変更内容とその理由の記録としてフォルダを openspec/changes/archive/YYYY-MM-DD-<name>/ に移動する。/opsx:reject/opsx:abandon という対となるコマンドは存在せず、アーカイブ形式の中に「この特定のアイデアは調査されて却下された」という未来の提案へのシグナルもない。このギャップが最も重要になるのは、OpenSpec が本来好適であるはずのコードベース、すなわち少数のコントリビューターと、定期的に同じアーキテクチャ上の質問(これら2つのサービスはマージできるか、この永続化レイヤーは共有できるか、このHTTP境界を直接インポートに置き換えるべきか)を再検討するエージェントが存在するブラームフィールド(既存)システムである。

新しい提案へフィードバックする階層化された決定アーカイブ

これは仮説的なギャップではない。これはOpenSpec自身のメンテナーに対して、機能リクエストとして直接提起され、その会話がどのように展開されたかを知っておくことで、独自の修正方法を即興で編み出す前に価値のある知見が得られる:プロジェクトが実際に結論付けたことが、どの規約を採用する価値があるかを形づくるからだ。本ガイドでは、/opsx:archive のみに依存した場合の起こりうる事象、OpenSpecのイシュートラッカーで既に交わされた実際の議論、そしてコアサポートを待ったり必要にされたりすることなく今日から採用できる軽量な decision.md パターンを概観する。

なぜアーカイブするだけでは却下された決定を記録できないのか

構築しなかったと判断した変更をアーカイブするだけでは、技術的には動作する——いずれの場合でもフォルダはアクティブなリストから移動されるからである。問題は、そのアーカイブされたフォルダが、リリース済みの変更と多数並ぶ状況で何のコミュニケーションも果たさない点にある:

  • ステータスフィールドの欠如。 アーカイブされた変更は、リリースされたものか、あるいは /opsx:propose の最初の3メッセージで放棄されたものか、外見上同じに見える。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年1月に、ファーストクラスのアーキテクチャ決定記録(ADR)サポートの要求として開かれた:単一の変更のライフサイクルに依存せず永続的に保持される記録により、却下されたり置き換えられたりした決定が、すべての未来の提案に対して可见なままになるようにするものである。コントリビューターはそれを実装するプルリクエストをオープンすることすら行った。

その後、リードメンテイナーのTabish Bidiwale(@TabishB)と深く関与するコミュニティメンバー数名が関わり、不変記録と可変記録、ADRが調査フェーズに属するのか設計フェーズに属するのか、一つの決定が後の十数の変更に影響を与えた場合のクロス変更所有権、そしてADRと仕様との関係(システムを「権威ある」形で記述するものとして)など、真に実質的な7ヶ月間の議論が続いた。Tabish Bidiwaleの初期のフレーミングが、スレッドが最終的に定着した方向性を設定した:OpenSpecはデフォルトで軽量さを保ち、ADRのような専門的なワークフローはコアに組み込むのではなく、スキーマシステムを通じて設定可能にすべきである。コミュニティメンバーは後日、議論が着地した場所を要約した:

ADRワークフローは価値があるが、OpenSpecには現在ファーストクラス/ネイティブのADRサポートがない…ここで議論された方向性は、デフォルトのワークフローを軽量にし、専門的なワークフローを設定可能にすることである。

メンテイナーのClay Good(@clay-good)は2026年8月にその基礎に基づいてイシューをクローズし、GitHub Discussion #1553 に移動して、未解決のバグとしてオープンなままにならないよう、会話が進化し続けることを可能にした。これは、そのピッチ全体がデフォルトでSpec Kitスタイルの儀式を回避することにあるツールにとって、合理的な判断である。それ同時に、修正は1レイヤー上の、2つの場所のいずれかに存在することを意味する:

  1. コミュニティスキーマ。 OpenSpec技術アドバイザーのHari Krishnan(@harikrishnan83)によって構築され、intent-driven.dev に文書化された spec-driven-with-adr スキーマは、OpenSpecのデフォルトの4成果物パイプラインに第5の成果物を追加する。これはデフォルトスキーマが、変更がアーカイブされた瞬間に design.md の根拠を失うため存在する——仕様デルタのみが前方に同期されるため、決定の「なぜ」は、何かがそれらを保持しない限り、変更とともに消えてしまう。
  2. リポジトリレベルの規約。 小さな、手製の decision.md ファイルと命名ルール。採用コストはゼロであり、カスタムスキーマのインストールを必要としない。

本ガイドの残りは、ほとんどのチームにとって低摩擦の出発点であり、かつ以下のコミュニティスキーマのセクションが示すように、拒否ログがそれを正当化するほど大きくなった場合に、後からその重いツールへ切り替えることと互換性があるため、オプション2を詳述する。

却下された変更を記録するための decision.md 規約

却下された調査は、リリースされたものと同じ構造にし、デルタの同期を行う前に手を止め、結果を平明に述べる1つのファイルを追加する:

openspec/
  changes/
    archive/
      2026-09-16-rejected-shared-persistence-layer/
        proposal.md
        decision.md

decision.md は、適切なアーキテクチャ決定記録が回答するのと同じ4つの質問——何が決定されたか、なぜか、どのような代替案があったか、何が答えを変えるか——に答える:

# Decision

Status: Rejected

## Decision

2つのGoサービス間のサービス間HTTP境界を、直接のパッケージインポートに置き換えないこと。

## Reasons

- 独立してデプロイされるサービス間のコンパイル時カプリングを増加させる。
- 永続化レイヤーを暗黙の、文書化されていない契約にする。
- 測定された利点(レイテンシ、コードの重複)は、このコードベースではカプリングコストよりも小さかった。

## Alternatives considered

- 共有内部Goモジュール —— 同じカプリング理由で却下。
- HTTPの代わりにgRPC —— 延期、却下ではない;HTTPオーバーヘッドが測定されたボトルネックになれば再検討。

## Reconsider only if

- 2つのサービスが意図的に1つのデプロイ可能単位にマージされるか、
- レイテンシ測定がHTTPホップが証明されたボトルネックであることを示す。

## Related

- アーキテクチャルール:サービスはHTTP経由で通信し、共有パッケージは使わない。

この規約全体を機能させる唯一の厳しいルール:却下された変更に対して同期ステップを実行しないこと。 /opsx:propose が変更を却下する前にデルタ仕様の草稿を作成していた場合、CLIがちょうどこの状況のために提供しているフラグを使用する:

openspec archive investigate-shared-persistence --skip-specs

--skip-specs は、openspec archiveopenspec/specs/ に一切触れず変更を整理するよう指示し、これはリリースせずにアーカイブするものにとって最も安全なデフォルトである。通常の同期プロンプトを代わりに受け入れると、却下されたアイデアのデルタ仕様が正規の仕様とマージされ、正規の openspec/specs/ はシステムが現在何をやるかを記述すべきであり、草稿化され却下されたすべてのアイデアを記述するべきではない。ある変更が構造的な理由で恒久的に仕様変更を生成しない場合——例えば純粋な調査フォルダ——OpenSpecはその変更の .openspec.yamlskip_specs: true を宣言することもサポートしており、フラグなしで毎回清潔にアーカイブできる。

人間とエージェントがアーカイブをスキャンできるように、却下された変更を命名する

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/          # shipped, no prefix needed

これは、独立した決定記録に推奨されているステータスの語彙——proposed(提案中)、accepted(承認)、superseded(代替)、deprecated(非推奨)——を、別々の docs/decisions/ フォルダではなく、OpenSpec自身のアーカイブに適用しているものと同じである。語彙は小さく保つこと。3つか4つの一貫したプレフィックスは、各提案が少し異なるスペルで記述する自由記述のステータス行より優れている。

エージェントが再び提案する前にアーカイブを確認させるには

命名と decision.md ファイルは、フォルダをスキャンする人間の発見可能性を解決する。それらは、エージェントが新しい提案を起草する前にアーカイブを検索させるには何もしない——それは明示的な指示でなければならず、/opsx:propose はデフォルトで行わず、整理されたファイル命名の程度だけでそれを変えることはできないからである。

その指示を置く2つの場所は、OpenSpecがプロジェクト固有のガイダンスを注入することを期待する方法に合致している:

openspec/config.yaml、すべての計画リクエストに注入される context: フィールドの下(OpenSpecクイックスタートでカバーされている50KBの上限に注意):

context: |
  変更を提案する前に、openspec/changes/archive 内の "rejected-" や "abandoned-" 
  がプレフィックスとして付いているフォルダを検索し、実質的に類似のアイデアを記述しているものを探す。
  もしそれが存在すれば、その decision.md を要約し、アイデアを再び提案する前に何が変わったかを述べる。
  新しい証拠なしに却下された決定を再検討しないこと。

AGENTS.md またはプロジェクト独自のエージェント指示書内、リクエストごとのコンテキスト塊ではなく、常設ルールとして:

## 却下された OpenSpec 変更

提案が調査され却下された場合:

1. そのデルタ仕様を同期または適用しないこと。
2. `decision.md` を追加し、Status、Decision、Reasons、
   検討されたAlternatives、および Reconsider only if を記載する。
3. アーカイブされたフォルダ名にプレフィックスを付ける:`rejected-<name>` または `abandoned-<name>`4. 実質的に類似の変更を提案する前に、`openspec/changes/archive/` を検索し、
   以前の決定を参照する。
5. 文書化された再検討条件が実際に変化していない限り、却下された決定を再開しないこと。
flowchart TD A[変更する価値のある新しいアイデア] --> B{openspec/changes/archive を検索} B -->|類似の却下決定が見つかった| C[以前の decision.md を要約] C --> D{再検討条件は変わった?} D -->|いいえ| E[再提案しない。決定を参照する。] D -->|はい| F["変更されたコンテキストを明記して /opsx:propose"] B -->|類似のものが見つからない| F

どちらの指示もコンプライアンスを保証するものではない——エージェントは検索ステップをスキップできるかもしれない、他の注入されたコンテキストを読むのをスキップできるのと同じ方法で。しかし、それは「情報がリポジトリのどこかに存在する」と「エージェントは毎回それを探しに行くよう指示される」の違いであり、実践において繰り返される調査を実際に減らすのは後者だけである。

実践例:提案を却下し、その後正しく再検討する

具体的なケースで部品を組み立てる。チームメイトが、ネットワークレイテンシを削減するために、サービス間HTTP呼び出しを直接Goパッケージインポートに置き換えるようエージェントに依頼했다고しよう。

  1. 調査し、提案する。 /opsx:explore は両方のサービスを読み、/opsx:propose replace-http-with-direct-import は提案、レイテンシの利得とカプリングコストを天秤にかける設計書、およびドラフトのデルタ仕様を作成する。
  2. 調査し、却下する。 設計書のレビューの後、チームはカプリングコスト——独立してデプロイされる2つのサービスがコンパイル時依存性を共有するようになること——が、実際の問題として誰も測定していないレイテンシの利得を上回ると決定する。何も構築されない。
  3. 同期なしでアーカイブする。 フォルダを削除する代わりに、openspec archive replace-http-with-direct-import --skip-specs を実行し、その後 Status: Rejected、上記の理由、そして答えを変える条件を特定する Reconsider only if 句(例えば、「レイテンシ測定がHTTPホップが証明されたボトルネックであることを示す場合」)を備えた decision.md をアーカイブされたフォルダに追加する。フォルダ名に rejected- プレフィックスを付けて openspec/changes/archive/2026-09-16-rejected-replace-http-with-direct-import/ と読み取れるようにリネームする。
  4. 数ヶ月後、誰かがそれを再び提起する。 別のコントリビューター、または新しいセッションで同じエージェントが、「チェックアウトから在庫への呼び出しを高速化する」よう依頼され、同じアイデアに酷似した提案を起草し始める。openspec/config.yaml がエージェントにまずアーカイブを検索するよう指示しているため、却下されたフォルダを見つけ、decision.md を読み、報告する:「2026-09-16に、カプリング理由で実質的に類似の変更が提案され却下されました。再検討条件は『レイテンシ測定がHTTPホップが証明されたボトルネックであることを示す場合』でした。新しい測定値がありますか、それともこれは別の問題ですか?」
  5. チームが新しい証拠を提供する。 プロファイリングが現在HTTPホップがチェックアウトレイテンシに本当に支配的であることを示している場合、それはまさに元の decision.md が求めていた変化しえた状況である。エージェントは /opsx:propose を進め、新しい提案の decision.md——これがまたアーカイブされたとき、承認されようが却下されようが——は Related 下に以前のものを参照するため、アーカイブは2つの無関係なフォルダがたまたま同じアイデアを記述しているのではなく、連続的な決定履歴として読み取れる。

この5番目のステップが、この規約の全要点である。これがないと、ステップ4は全く起こらない——エージェントがゼロから再調査するだけ——か、あるいは運よく起こる——人間が以前の会話を覚えていたからである。decision.md ファイルとアーカイブ検索指示は、「誰かが覚えていたかもしれない」を、ワークフローが実際にチェックするものに変える。

OpenSpecのアーカイブと専用ADRログ:何が何を所有するか

アーカイブ内で decision.md ファイルをメンテナンスしている場合、規約が静かに重複ドキュメントに変わらぬよう、どの成果物がどの質問に答えるかを明示する価値がある:

成果物 回答する質問
openspec/specs/ システムは現在何をするか?
openspec/changes/<name>/ (アクティブ) 私たちは今、何を変わるよう提案しているか?
openspec/changes/archive/<name>/ 過去に何が変更(または却下)され、なぜか?
docs/adr/ (独立、ツール中立) 私たちは、単一の変更の独立した永続的なアーキテクチャルールを学んだか?

一つの調査に属するほど狭い決定——「この永続化レイヤーの共有を検討し、ノーと言った」——に対しては、上記のアーカイブ内の decision.md 規約で十分である。多くの未来の変更を超えて生き残り、制約するべき決定——「サービスはHTTP経由で通信し、決して共有パッケージを使わない」——に対しては、それを docs/adr/ に独立したアーキテクチャ決定記録として昇格させ、却下された変更の decision.mdRelated 下でそれを参照するようにする。この分離により、OpenSpecのアーカイブは個別の調査に焦点を当て、ADRログは単一のツールのライフサイクルを超えて生き残るべき少数のルール——OpenSpecからの完全なマイグレーションを含み——を保持する。

いつ spec-driven-with-adr スキーマを代わりに採用すべきか

上記の手製の規約はコストがゼロであり、15分の設定内に収まるため、正しいデフォルトである。しかし、命名プレフィックスを超えて成長したと決定する前に、より構造化された代替案が実際に何をするか理解する価値がある。

spec-driven-with-adr は、OpenSpecのパイプラインにおいて designtasks の間に第5の成果物 adr を挿入する。変更フォルダに直接ADRコンテンツを書くのではなく、adr ステップは短い変更ローカルな adr.md レビューマニフェストを生成し、変更が真に永続的なアーキテクチャ上のコミットメントを導入する場合、リポジトリルートに番号付き記録—— /adr/0042-use-postgres-for-catalog.mdopenspec/ と兄弟、内部にはネストしない——を生成する。スキーマが作成するすべてのADRは、承認されると不変である:スキーマ自身の指示はこれを「鉄則」と呼んでいる——承認された記録のステータス、本文、日付を編集してはならない。以前の決定を変更するには、古いものに対して Supersedes: フィールドで名前を付ける新しい ADRを書き、将来の設計はその取代チェーンをたどって、どの決定がまだ有効であるかを把握する。これは、上記の decision.md 規約の「再検討するのは~の場合のみ」のアイデアのより厳密なバージョンであり、人間が書き留めることを覚えておくのに依存するのではなく、スキーマによって強制される。

このスキーマが解決するものとしないものを正確に区別する価値がある。それは、承認され、アーカイビング後も生き残るべき決定——DynamoDBではなくPostgres、セッションCookieではなくJWT——のために構築されている、ではなく、何もリリースせずに調査され却下された提案のためではない。却下された調査も、このスキーマの下には明らかな居場所がない;このガイドからの同じ decision.md と命名規約を重ね、単独の docs/adr/ フォルダではなく /adr/ 記録を参照するだけである。

これらに気づいたら、それを手にする:

  • 却下された決定の数が大きくなり、プレフィックスで openspec/changes/archive/ をグレープしても高速でなくなっている。
  • 永続的なアーキテクチャ上の決定を、規約と grep ではなく、自動的にすべての新しい設計に対して検証しクロスリファレンスしたい。
  • 複数のコントリビューターがわずかに異なる decision.md の形を発明し続け、スキーマによって1つの不変で番号付きフォーマットを強制したい。

カスタムスキーマのインストールは命名規約よりも大きなコミットメントであり——却下されたものだけでなく、すべての未来の変更で /opsx:propose が生成するものを変える——軽量版が明らかに逼迫しているときの上級ステップとして扱い、デフォルトの第一歩として扱わないこと。

結論

OpenSpecのアーカイブは、一つの成果物——リリースされた変更——を前提に設計され、そのメンテイナー自身は、7ヶ月の公開的な議論の後、ファーストクラスの却下またはADRサポートはすぐにはコアワークフローにやってこないことを明確にしている。これは、修正をOpenSpecがすでに多くのチーム規約を置く場所——ツールではなく、あなたのリポジトリ内——に残す。decision.md ファイル、アーカイブ時の --skip-specs フラグ、rejected-/abandoned- 命名プレフィックス、そして提案する前にアーカイブを検索するようエージェントに指示する明示的な指示は、ほとんどの繰り返される調査を止めるために十分である。spec-driven-with-adr スキーマは、その軽量規約が追跡している決定の数に対して真に逼迫したときにのみ手にする——そしてそのときでさえ、区別を明確に保つ:それはあなたが承認し、アーカイビング後も生き残らせたい決定を管理するものであり、却下したものではない。

関連リンク

購読する

システム、インフラ、AIエンジニアリングの新記事をお届けします。