


大きなフルスタックのリポジトリで、AIエージェントに変更を出す時の決まりを守らせる
型付きのフロントエンドとバックエンドがある大きなリポジトリで、AIエージェントに作業させる時に使う。プッシュ前に pre-commit のチェックを通し、移行先の書き方でコードを書き、セキュリティの指摘はロールごとにできる事で判断し、テスト・ドキュメント・プルリクエストをプロジェクトの決まりどおりに仕上げる。
このAIルールを使うには
## プッシュの前に、毎回 pre-commit のチェックを通す
コミットをプッシュする前に、必ずリポジトリの pre-commit スイートを全ファイルに対して実行する。pre-commit チェックが失敗すると継続的インテグレーションも失敗するため、これは好みの問題ではなく、譲れないゲートである。
効率的な実行方法:
- まず変更をステージする。pre-commit はステージ済みファイルだけを検査するため、ステージしていない編集は黙って飛ばされる。
- 素早い内側のループを回すには、ステージ済みファイルに対してスイートを実行するか、名前を指定した単一のフック(型チェッカー、フォーマッター、リンター)を実行する。プルリクエストを作成・更新するプッシュの前には、全ファイル対象のパスを実行する。
- 実行前にプロジェクトの仮想環境またはツールチェーンのシェルを有効化する。よくある置き場所は開発者ごとに異なるため、コマンドが見つからない場合はパスを推測せず、どの環境を有効化すべきかユーザーに尋ねる。
- 一部のフックは自動修正する(フォーマッター、行末の空白)。最初の実行は自分がすでに修復した内容を失敗として報告するため、修正されたファイルを再ステージして再実行する。
失敗は3種類を想定する: 自動修正されるフォーマットの問題、手動修正が必要な型チェッカーのエラー、手動修正が必要な lint のエラー。
## 新しいコードは、古い書き方でなく移行先の書き方で書く
いくつもの移行が現在進行中である。古いパターンに一致するコードはまだ存在するが、その存在はそれをさらに書いてよいという許可ではない。新規コードと変更するコードは、移行先のパターンに従う。
- 型付きフロントエンド: 逃げ道としての `any` 型を使わず、型のない新規スクリプトファイルも作らない。型付きの方言で書き、既存の型定義を再利用する。
- 共有コンポーネント層: UI コンポーネントはサードパーティのライブラリから直接ではなく、プロジェクト自身のデザインシステムパッケージからインポートし、レガシーなものより デザインシステムのテーマトークンを優先し、独自の CSS ではなくコンポーネントライブラリがサポートするスタイリングを使う。
- テストピラミッド: 統合テストより単体テストを、エンドツーエンドテストより統合テストを優先する。新しいエンドツーエンドテストは採用済みのフレームワークで書く。置き換えられた側のエンドツーエンドフレームワークは非推奨であり、移行の完了をもって取り扱いを終える。
- バックエンドの型付け: 新規コードはすべて型ヒントを持ち、モデルは適切なアノテーションを使い、型チェッカーが通らなければならない。
- 識別子の移行: 新しいモデルは主キーに不透明な一意識別子を使い、公開 API は内部の連番整数ではなくその識別子を公開し、既存のモデルには段階的な切り替えのために整数の識別子と並べて新しい識別子を追加する。
## セキュリティの指摘を、ロールごとにできる事で判断する
セキュリティ上の問題についてコードパスを評価する前に、リポジトリの正本となるセキュリティポリシー文書を読む。これはセキュリティモデルの権威ある情報源であり、人間の報告者も自動スキャナーもこれを基準に評価される。
指摘がスコープ内かどうかを判定する唯一のテストはこれである: セキュリティポリシーのロールとケーパビリティのマトリクスが与えていない操作を、あるプリンシパルが実行できてしまうか? 答えが「はい」ならスコープ内。「いいえ」ならスコープ外。
そのテストを枠づける信頼境界が3つある:
1. 管理者ロールは完全に信頼された運用上のプリンシパルである。文書化された設定・API・UI を通じて管理者ができることは、脆弱性ではなく意図された機能である。
2. オペレーターはデプロイ時の判断を所有する: シークレット、ネットワークの露出、フィーチャーフラグの選択、コネクタとコーデックの選択、通知先、サードパーティのプラグイン。この層での設定ミスは製品の脆弱性ではなく、デプロイ上の欠陥である。
3. コードベースは、プリンシパルに機能を公開するあらゆる場所でロールとケーパビリティのマトリクスを強制する責任を負う——API ルート、コマンド層とデータアクセス層、UI ハンドラー、バックグラウンドジョブ、その他すべてのエントリーポイント。強制チェックの欠落や誤りは、どこにあろうとスコープ内である。
このモデルは、オペレーターが管理するインフラ——メタデータデータベース、キャッシュ、メッセージブローカー、シークレットストア、デプロイ環境——がオペレーターの信頼境界の内側にとどまることを前提とする。有効な指摘は、それらのシステムをすでに掌握しているわけではない攻撃者による境界侵害を実証しなければならない。
## ルートとデータの種類ごとに、正しい権限チェックを使う
ルートレベルの認可はルートの種類ごとに1つのデコレータを使い、どれが正しいかはルートの種類によって決まる: 最新の REST API 面向けのもの、レガシーな JSON ビュールート向けのもの、レガシーな HTML ビュールート向けのものである。これらを取り違えることは、チェックが存在するように見えても強制のバグである。
オブジェクトレベルの認可は、これとは別の第2のゲートである。データを持つリソース——ダッシュボード、チャート、データセットとデータソース、クエリ、データベースおよびテーブルへのアクセス、クエリコンテキスト——に適用され、セキュリティマネージャーのアクセスチェックを通じてオブジェクトごとに呼び出される。特定のデータ保持オブジェクトを返す、または変更するルートでオブジェクトごとのゲートを省略しているコードはスコープ内である。
その他のリソース——アノテーション、タグ、スタイルテンプレート、レポート、行レベルセキュリティのルールなど——は、ルートレベルのデコレータに加えてデータアクセス層のベースフィルタによる所有者スコープに意図的に依存している。これらのリソースにオブジェクトごとのチェックが無いのは設計どおりであり、指摘には当たらない。
リソースの種類に応じた正しい認可パターンに従っていても、そのコードが他の問題から解放されるわけではない。インジェクション、サーバーサイドリクエストフォージェリ、クロスサイトスクリプティングなどの種類は認可とは無関係であり、別途評価される。
## 自動スキャナーの指摘に、破られた決まりと攻撃者のロールを書かせる
自動スキャナー——モデルベースのコードスキャナー、静的解析ツール、依存関係ツール——は、このコードベースに対して提出するすべての指摘において、次の2つを明示的に示さなければならない:
1. セキュリティポリシーのロールとケーパビリティのマトリクスのうち、その指摘が違反していると考える具体的な行。
2. その指摘が攻撃者に想定しているプリンシパル: 未認証もしくは一般利用者のプリンシパル、低権限の認証済みロール、クエリツールのロール、権限の高い作成者ロール、管理者ロール、埋め込み用ゲストの資格情報、または明示的なケーパビリティ付与を伴う名前付きのカスタムロール。
その両方を特定できない指摘は、脆弱性としてではなく質問として提出しなければならない。この要件は、報告されるあらゆる問題が公開されたセキュリティモデルに照らして検証可能であるようにし、憶測やパターン一致だけの報告をトリアージのキューに入れないために存在する。
## フロントエンドとバックエンドのコードの決まりを守る
フロントエンド: `any` を避けて既存の型を再利用する。フックを使った関数コンポーネントで書く。UI コンポーネントはサードパーティのライブラリを直接インポートするのではなく共有のデザインシステムパッケージから取る。すでに廃止されたレガシーなレンダラーではなく、プロジェクト標準のテストランナーとテスティングライブラリを使う。グローバルストアはすでに存在する場所では使い、それ以外ではローカルなフックの状態を使う。
バックエンド: 新規コードにはすべて型ヒントが必須で、静的型チェッカーが通らなければならず、データモデルは適切な型付けを持ち、テストにはプロジェクト標準のテストフレームワークを使う。クエリを組み立てるときは、真偽値カラムを false リテラルと比較する(リンターが指摘する)のではなく、ORM の否定演算子を使う。
ライセンスヘッダー: 新規ソースファイルにはプロジェクト標準のライセンスヘッダーが必要である。エージェント指示ファイル(このファイルとベンダーごとの同種ファイル)は、ヘッダーにトークンを費やさないよう、意図的にこの要件から除外されている。
コメント: 「now」「currently」「today」のような時点に依存する表現は陳腐化するため避ける。いつ読まれても正確であり続けるコメントを書く。
## コードを変えたら、ドキュメントと破壊的変更の記録も直す
ドキュメントは変更の一部であり、後回しのタスクではない:
- ユーザーから見える変更については、ドキュメントツリーを更新する。
- 破壊的変更は専用のアップグレードノートのファイルに記録し、オペレーターが1か所で見つけられるようにする。
- 新しい関数とクラスにはすべて docstring を書く。
オペレーターやエンドユーザーが観測できる挙動に触れる変更では、対応するドキュメントの編集を欠いたプルリクエストは未完成である。
## 自動で作るコンポーネントのドキュメントは、ジェネレーターでなくストーリー側で直す
開発者ポータルは、コンポーネントカタログのストーリーからコンポーネントのドキュメントを自動生成する。ストーリーが唯一の情報源であり、そこから2つのルールが導かれる。表示が正しくないときはジェネレーターではなくまずストーリーファイルを直すこと、そしてジェネレーターを軽量に保つこと——ジェネレーターはストーリーのデータを抽出して受け渡すだけなので、コンポーネントごとの特別扱いを追加したくなる誘惑に抗う。
コンポーネントのドキュメントが正しく生成されるためには、そのストーリーファイルは次を満たさなければならない:
- メタデータオブジェクトを変数に代入してその変数をエクスポートするのではなく、デフォルトエクスポートとしてインラインでエクスポートする。
- インタラクティブなストーリーには、一貫した接頭辞とコンポーネント名を組み合わせた名前を付ける。
- デフォルトの prop の値はストーリーの引数の中で定義する。
- 引数の型は、メタデータのレベルではなくストーリーのレベルで、コントロールの型と説明を含めて定義する。
- バリアントのグリッド、必要なコンポーネントのためのサンプルの子要素、カスタムのライブコードブロック、インラインでは解析できない複雑なオブジェクトの prop については、文書化されたパラメータキーを使う。
ドキュメントの問題を診断するときは、ジェネレータースクリプト、そのラッパーコンポーネント、生成物の出力ディレクトリの3つを可動部分として念頭に置く。
## テストの準備を自作せず、用意されたテストヘルパーを使う
リポジトリはヘルパーを同梱している。セットアップを自作せずそれらを使う。バックエンドでは、共有のテストベースクラス、設定をモックしフィーチャーフラグを切り替えるためのデコレータ、指定したロールでログインするための認証ヘルパー、テストが必要とするフィクスチャを作るためのファクトリーヘルパーがそれにあたる。フロントエンドでは、標準のプロバイダーを組み込むカスタムの render ヘルパー、ストア・ルーター・テーマ用のラッパーファクトリー、select 操作のヘルパーがそれにあたる。
モックのルール: 設定オブジェクトにはプレーンなモックを使い、テスト対象のコードが同期的なときに非同期モックに手を伸ばさない。モデルに新しいフィールドが加わったら、API テストの期待カラム一覧を更新する。
各スイートの実行方法を把握しておく: フロントエンドのスイート全体、フロントエンドのテストファイル1つ、バックエンドのテスト全体、バックエンドのテストファイル1つ、バックエンドのテストのディレクトリ1つ、そしてエンドツーエンドのスイートをヘッドレス・インタラクティブ・ヘッデッド・デバッグの各モードで実行する方法。
バックエンドのテストが、テスト対象のコードではなくデータベースや環境のセットアップが原因で失敗する場合は、ユーザーの環境をその場しのぎで直そうとせず、ユーザーにテスト環境のセットアップを実行してもらうよう依頼する。
## デバッグの前に、ヘルスエンドポイントで環境を確かめる
まず簡単なセットアップ確認を実行する。アプリケーションのヘルスエンドポイントを叩き、応答することを確認してからバグ報告に時間を使う。ヘルスチェックの失敗は、たいていコードが壊れているのではなく、ワークスペースがそもそもセットアップされていないことを意味する。
ヘルスチェックが失敗したら、自分でユーザーの環境を修復しようとせず、環境がセットアップされていないように見えることをユーザーに伝え、エージェントと作業するためのプロジェクトの文書化されたセットアップ手順を案内する。
現在地を把握する際は、主要なプロジェクトファイルを押さえておく: ビルド・テスト・lint のスクリプトと開発サーバーのポートが書かれたフロントエンドのパッケージマニフェスト、リンターと型チェッカーの設定が書かれた Python のプロジェクトファイル、そしてベース用と開発用に分かれた依存関係の requirements フォルダ。
## プルリクエストはテンプレートを全部埋め、conventional commits 形式のタイトルにする
プルリクエストを作成するときは:
1. 起草する前に、リポジトリにある現在のプルリクエストテンプレートファイルを読む。テンプレートは時とともに変わるため、キャッシュした内容を使い回さず、必ず実ファイルを読む。
2. テンプレートが定義するすべてのセクションを埋める——概要、変更前後の証跡、テスト手順、追加情報。
3. プルリクエストのタイトルは conventional commits 形式 `type(scope): description` で付ける。例: `fix(dashboard): load charts correctly`。有効な type は `fix`、`feat`、`docs`、`style`、`refactor`、`perf`、`test`、`chore` である。
## 慣れない場所を直す前に、フォルダの配置とファイルの置き方を覚える
大規模なリポジトリで変更を正しい場所に収めるには、2つの習慣が効く。第一に、編集の前にディレクトリの地図を覚えること: バックエンドのアプリケーションとその API エンドポイント・データモデル・コネクタがどのツリーにあるか、フロントエンドのソースとそのコンポーネント・チャートビルダー・ダッシュボード・クエリエディタの領域がどのツリーにあるか、共有のデザインシステムパッケージがどこにあるか、そしてテスト・ドキュメント・破壊的変更ログがどこにあるか。
第二に、新機能が慣例どおりのファイルに収まるよう、繰り返し現れるファイルのパターンを知っておくこと: デコレータとスキーマを生成する docstring を伴うエンドポイントのための API モジュール、生成される API 仕様に供給されるリクエストとレスポンスの検証のための schemas モジュール、トランザクションで包まれたビジネスロジックのための commands 層、永続化のための models 層。生成される API ドキュメントはそれらの docstring とスキーマから導出されるため、docstring の更新を伴わないエンドポイントの変更は、気づかれないままドキュメントの質を落とす。
データベースのマイグレーションには独自の慣例がある: マイグレーションの versions ディレクトリに置かれ、タイムスタンプ・リビジョンハッシュ・説明を含む名前を付け、データベースエンジンをまたいで互換性を保てるよう、生の ORM 操作ではなく共有のマイグレーションユーティリティヘルパーを呼び出すべきである。
最後に、このリポジトリは異なるエージェントベンダー向けに並列の指示ファイルを保持していることに注意する。それらすべてに当てはまるルールを変更するときは、内容を一貫させること。
