制約駆動開発
概要
このパックの他のスキルは、良い状態がどのようなものかを説明します。code-review-and-qualityは5つの軸を提供し、test-driven-developmentはサイクルを提供し、security-and-hardeningは脅威リストを提供します。これらはすべてエージェントが読む可能性のある散文として存在し、セッションの終了後には残りません。
このスキルは異なるものを生成します。このプロジェクトの品質基準を、数値を伴った文書として記録し、会話よりも長く生き残り、機械的にチェックできるようにします。
その理由は重要です。あなたがコードを書いたときは、それを読めば良し悪しがわかりました。エージェントはあなたがその週に読むよりも多くのコードを半日で書くため、判断はあなたの頭の中から、ループ内で実行されるチェックに移ります。そのチェックは存在しなければならず、あなたが実際に選んだ数値が必要であり、エージェントが自身の出力を修正できるように作業に十分近いタイミングで実行される必要があります。
仕様駆動開発は何を構築すべきかを定義します。テスト駆動開発はそれが機能することを証明します。制約駆動開発は、プルリクエストで誰かが議論する前に、「出荷に十分な品質」が何を意味するかを定義します。
使用するタイミング
以下の場合にこのスキルを適用します:
- プロジェクトや重要な機能を開始する際に、品質基準が文書化されていない場合
- ユーザーが「制約を設定して」「品質ゲートを追加して」「標準を定義して」「エージェントがジャンクを出荷するのを止めて」と依頼した場合
- エージェントが誰も行単位で読んでいない量のコードを生成している場合
- CIにチェックはあるが、どれがマージをブロックし、どれが飾りかを誰も言えない場合
- カバレッジ、パフォーマンス、アクセシビリティの数値がPRごとに議論され、一度も決定されない場合
/build autoや任意の自律ループを実行しようとしており、メインブランチに到達するのを防ぐ唯一のものが、エージェント自身が書いたテストスイートである場合
使用すべきでない場合:
- プロジェクトに既に
CONSTRAINTS.mdがあり、ユーザーがそれを変更していない場合 — 代わりにそれを読んで従うこと - 使い捨てのスクリプト、スパイク、捨てる試作品
- ユーザーが今すぐコードレビューを望んでいる場合(
code-review-and-quality)またはCIパイプラインを構築したい場合(ci-cd-and-automation) - 予想寿命が2週間のプロダクトマーケットフィット前のコード — 以下のフロアはまだ価値がありますが、残りはそうではありません
制約の読み込み
インタビューには生きているユーザーが必要です。非対話型のコンテキスト(CI、/loop、自律実行)では実行しないでください。制約が欠落しており、そのようなコンテキストにいる場合は、以下のフロアを適用し、適用したことを注記し、残りを人間にフラグします。
プロセス
ステップ 1: 尋ねる前に検出する
読めるものを決して尋ねないでください。最初の質問の前に、以下を収集します:
| 項目 | 確認場所 |
|---|---|
| 言語とスタック | package.json、pyproject.toml、go.mod、Cargo.toml |
| テストランナー | 開発依存関係、testスクリプト、既存のテストファイル |
| 既存のリンター | eslint.config.*、biome.json、.ruff.toml |
| 現在のカバレッジ | coverage/出力、またはスイートを一度実行 |
| CI | .github/workflows/、.gitlab-ci.yml |
| エージェントハーネス | .claude/、.codex/、AGENTS.md |
見つけた内容を2行で報告し、残ったものだけを尋ねます。
ステップ 2: 4つの質問、それぞれにデフォルト値
interview-meの1回に1つの質問の規律に従いますが、1つの変更があります。ここでのすべての質問にはデフォルト値があり、「わかりません」という回答でも動作する設定が生成されます。
Q1: フロアに加えて、以下のうちどれを強制しますか?
(a) 新しいコードのテストカバレッジ
(b) セキュリティスキャン
(c) パフォーマンス予算
(d) アクセシビリティ
(e) アーキテクチャ境界
推定: (a) と (b) — 既にテストランナーがあり、ユーザー入力を処理しています。
不明な場合のデフォルト: (a) と (b)。
各選択のコストを伝えます:(c) と (d) には実行中のURLが必要、(e) にはルールファイルの作成が必要。
Q2: エージェントがタスク実行中にチェックが失敗した場合、ブロックするべきですか、それとも警告するべきですか?
推定: ブロック。無人でエージェントを実行しており、誰も読まない警告は単なる警告です。
不明な場合のデフォルト: フロアではブロック、それ以外は最初の2週間は警告。
Q3: 目標の数値を考えていますか、それとも現在の状態を測定してそのラインを維持するべきですか?
推定: 測定。ほとんどのチームは数値を持っておらず、でっち上げられた数値は無視されます。
不明な場合のデフォルト: 測定して維持。以下の「ラチェット」を参照。
Q4: エージェントが作業を戻す前に許容できる最も遅いチェックは何ですか?
推定: 約90秒。それより長いと実行をやめてしまいます。
不明な場合のデフォルト: タスク終了時は90秒、CIでは無制限。
4つで止めます。12の質問からなる取り込みは、誰も理解できない設定と、始めたことを後悔するユーザーを生み出します。
ステップ 3: CONSTRAINTS.mdを書く
リポジトリルートに1つのファイル。任意のハーネスの任意のエージェントがそれを読むことができ、その変更はレビューに表示されます。
# 制約
最終確認日: 2026-08-08 by @mukhon-core
## フロア(常に強制、セットアップ不要)
- 新しい抑制コメントの禁止: `@ts-ignore`、`eslint-disable`、`# noqa`、`# type: ignore`
- 未実装スタブの禁止: `throw new Error("Not implemented")`、空の`catch {}`
- コミットメッセージに理由がない限り、テストのスキップまたは削除の禁止
- ソース内のシークレットの禁止
- 変更を通過させるためにこのファイルを弱めてはならない
## 数値で強制
| 次元 | ルール | チェック元 | 実行タイミング |
|------|--------|-----------|----------------|
| 型 | ゼロ型エラー | `tsc --noEmit` | 編集ごと |
| リント | 設定からのゼロエラー | `biome check` | 編集ごと |
| シークレット | ソース内のシークレット禁止 | `gitleaks detect --redact` | 編集ごと |
| カバレッジ | 変更行 ≥ 80% カバー | `vitest run --coverage` + git diff | タスク終了時、CI |
| セキュリティ: コード | 高重要度の検出結果なし | `semgrep scan --config p/default` | CI |
| セキュリティ: 依存関係 | 高以上なし | `osv-scanner scan source -r .` | CI |
| アクセシビリティ | 重大または深刻ゼロ | `axe $PREVIEW_URL --tags wcag2a,wcag2aa,wcag21aa` | プレビューデプロイ |
| パフォーマンス | LCP ≤ 2500ms、CLS ≤ 0.1 | `lighthouse $PREVIEW_URL --output=json` | プレビューデプロイ |
すべての行は、判定を生成するコマンドを指定します。数値があるがこの列にコマンドがない次元は、願望であり制約ではありません。
## 測定済み、まだ強制されていない
| 指標 | 現在値 | 方向性 |
|------|--------|--------|
| プロジェクトカバレッジ | 62.4% | 低下させてはならない |
| バンドルサイズ(メイン) | 184 kB | 増加させてはならない |
## 例外
| ID | ルール | パス | 理由 | 所有者 | 有効期限 |
|----|--------|------|-------|--------|----------|
| W1 | `no-explicit-any` | `src/legacy/**` | 書き換えはENG-441で追跡 | @mukhon-core | 2026-11-01 |
次に、AGENTS.mdとCLAUDE.mdに1行追加します:Read CONSTRAINTS.md before writing code. Do not weaken it to make a change pass.
ステップ 4: 各次元に必要なものをインストールする
次元を選択することは、何かをインストールすることを意味します。数値だけを残してメカニズムを残さないようにせず、事実上の標準が存在する場合に独自のチェッカーを発明しないでください — これらのツールがリストされているのは、そのルール形式と閾値がエコシステムの他のすべてがターゲットとするものであり、チームの既存の設定が機能し続けるためです。
| 次元 | ツール | インストール | 実行 | ゲート条件 |
|---|---|---|---|---|
| 型(TS) | tsc | 既存 | tsc --noEmit | 任意のエラー |
| 型(Python) | mypy | pip install mypy | mypy . | 任意のエラー |
| リント | 既存の設定 | 既存 | eslint . / biome check / ruff check | 任意のエラー |
| カバレッジ(JS) | テストランナー | 既存 | vitest run --coverage(またはjest --coverage) | 変更行のカバレッジ |
| カバレッジ(Python) | pytest-cov | pip install pytest-cov | pytest --cov --cov-report=lcov | 同上 |
| セキュリティ: コード | Semgrep | pipx install semgrep | semgrep scan --config p/default --config p/owasp-top-ten | 任意の高重要度検出結果 |
| セキュリティ: シークレット | gitleaks | brew install gitleaks | gitleaks detect --redact --no-banner | 任意の検出結果 |
| セキュリティ: 依存関係 | osv-scanner | brew install osv-scanner | osv-scanner scan source -r . | 高以上 |
| パフォーマンス: ページ | Lighthouse | npm i -D lighthouse | lighthouse $URL --output=json --quiet | LCP、CLS、パフォーマンススコア |
| パフォーマンス: バンドル | size-limit | npm i -D size-limit | size-limit --json | エントリごとのバイト予算 |
| アクセシビリティ | axe-core | npm i -D @axe-core/cli | axe $URL --tags wcag2a,wcag2aa,wcag21aa | 重大または深刻ゼロ |
| アーキテクチャ | dependency-cruiser | npm i -D dependency-cruiser | depcruise --validate src | 任意の違反 |
| アサーション品質 | Stryker | npm i -D @stryker-mutator/core | stryker run --mutate <changed files> | 突然変異スコア |
スキップすると問題を引き起こす5つのこと:
- gitleaksの
--redactはオプションではありません。 これがないと、一致したシークレットがエージェントのトランスクリプトに残り、漏洩したキーがログ、サマリー、またはコミットメッセージに含まれる方法です。ルールと場所を報告し、値を決して報告しないでください。 - LighthouseとaxeにはURLが必要です。 これらは実行中のアプリに対してのみ機能するため、プレビューデプロイまたは最初に起動するローカルサーバーに対して、ランタイムステージに属します。プロジェクトにヒットするURLがない場合(CLI、ライブラリ、デスクトップアプリ)、そのことを伝え、実行できないチェックを発明する代わりにその次元をドロップしてください。
- 高価なものは差分にスコープを絞ります。
stryker run --mutateをリポジトリ全体で実行すると数時間かかり、オフにされます。変更が触れたファイルに限定すると1分未満です。パスリストを受け取るSemgrepも同様です。 - カバレッジには2回目のテスト実行は必要ありません。 スイートが既に書き込むlcovを読み、それを
git diffと交差させます。数値を得るためにスイートを2回実行することは、人々にこれを嫌わせる最も速い方法です。 - Semgrepのレジストリルールは実行が無料です。再配布する前にライセンスを確認してください。
opengrepは同じルール形式とJSON出力を持つドロップインフォークであり、法務チームにとって重要な場合があります。
プロジェクトの独自のスクリプトにそれぞれを追加して、エージェントなしで再現可能にします:
{
"scripts": {
"check:fast": "tsc --noEmit && eslint . && gitleaks detect --redact --no-banner",
"check:task": "npm run check:fast && vitest run --coverage",
"check:full": "npm run check:task && semgrep scan --config p/default && osv-scanner scan source -r ."
}
}
このマッピングはツール自体よりも重要です。check:fastは編集後に実行され、check:taskはエージェントが完了したと判断したときに実行され、check:fullはCIで実行されます。
コマンドは現在2つの場所に存在します — CONSTRAINTS.mdのChecked by列とこれらのスクリプトです。CONSTRAINTS.mdが正規のソースです。各コマンドとともに理由を保持し、レビューに表示されます。スクリプトはそれをミラーリングする便利なラッパーであり、第二の真実のソースではありません。ずれた場合、ファイルが優先されます。
ステップ 5: ライフサイクルに配線する
最大の間違いは、すべてをどこでも実行することです。エージェントを停滞させるチェックはオフにされ、人々がオフにしたゲートはゲートがないよりも悪いです。なぜなら、基準がまだ存在するように見えるからです。
| フェーズ | コマンド | 実行内容 | 予算 |
|---|---|---|---|
| ビルド | /build | 型、リント、シークレット、フロア | 5秒未満、変更ファイルのみ |
| 検証 | /test | 関連テスト、変更行のカバレッジ | 90秒未満 |
| レビュー | /review | すべて、および以下のガード | 数分 |
| 出荷 | /ship | 方向性チェック、回帰なし | CI |
これを許容可能に保つ2つのルール:
- 差分にスコープを絞る。 この変更が触れた行をチェックし、リポジトリ全体ではありません。変更行のカバレッジはエージェントが動かせる数値です。プロジェクトカバレッジは継承したものです。
- コストが配置を決定する。 数秒を超えるものは編集ループから移動します。リポジトリ全体での突然変異テストには数時間かかりますが、変更が触れたファイルに限定すると1分未満です。これは人々が実行するチェックとそうでないものの違いです。
ステップ 6: 基準そのものを守る
誰かが指摘するでしょう — エージェントがコードとチェックの両方を書くなら、チェックは何も証明しません。半分正しく、それに対処する価値があります。
エージェントは巧妙な抜け穴を作りません。赤いチェックに遭遇し、最も安価な方法でグリーンに到達しようとします。レビュー時に、差分で以下の5つの動きを監視します:
- 閾値が変更された。 予算が引き下げられ、重要度が下げられ、高速ステージからチェックが削除されました。
CONSTRAINTS.mdをブランチポイントでの状態と比較します。 - テストが簡単になった。
.skipが追加され、テストファイルが削除され、残ったテストからアサーションが削除されました。 - チェッカーが黙らされた。 新しい
@ts-ignoreまたはeslint-disable。特に注意すべき4つの抑制は、依存しているチェックをオフにするためです:istanbul ignoreはコードをテストする代わりにカバレッジからドロップし、Stryker disableは生き残った突然変異体を隠し、nosemgrepとgitleaks:allowはセキュリティ検出結果に対してそれを行います。 - 作業が未完了。 スローするスタブ、失敗を沈黙に変える空の
catch、実装があるべき場所に立つTODO。 - 例外が出現した。 誰も議論していない例外テーブルの新しい行。
これにはgit diff以上のツールは必要ありません。基準を強化することは静かに行われるべきであり、緩めることは大きな音を立てるべきです。
番号付けされた次元とは異なり、フロアには独自の事実上のツールがありません。そのため、それを強制するように依頼されたエージェントはゼロからチェッカーを書く傾向があり、2つのエージェントは2つの異なるものを書きます。これらの5つのチェックのリファレンス実装は、references/floor-guard.mdでこのスキルに付属しています(差分スコープ、終了コード0/1/2、エコシステムごとに適応可能なパターン)。ゼロから発明するのではなく、それを適応させてください。すべての次元が事実上のツールを指定するのと同じ理由で:メカニズムが実行とスタック間で同じになるように。
すべてのチェックが等しく循環的であるわけではありません。 1つの質問でランク付けします — エージェントは機能しないコードを書いてこれをパスできますか?
- 外部 — axe-coreはWCAGをエンコードし、
osv-scannerは脆弱性データベースを読み、Lighthouseは実際のブラウザを測定します。エージェントはこれらに反論できません。 - プロジェクト — あなたのリントルール、レイヤー境界。人間がファイルを所有します。
- スイート — あなた自身のテスト。最も有用で、唯一本当に循環的なものです。
[truncated for translation]