


フルスタックのTypeScriptモノレポを直し、LLM機能は意味でテストする
LLM機能を持つTypeScriptのモノレポをAIに直させる時に使う。CIと同じパッケージ単位のチェックだけを回し、動きをテストし、個人の情報を広いログに残さず、LLMの答えを言い回しでなく意味で確かめる。
このAIルールを使うには
## CIと同じ、パッケージ単位のコマンドとチェックだけを回す
何かを実行する前に、リポジトリで文書化された開発、ビルド、リント、フォーマット、テスト、統合テスト、評価の各コマンドを確認する。ルート全体を対象とするツールで代用せず、変更対象のワークスペースに対応したパッケージ固有のコマンドを使う。
- 単一のテストは、対応しているパスまたは名前フィルターを指定して実行する。
- AI評価はリポジトリのルートから、AIパッケージ専用の評価コマンドで実行する。
- アプリケーションのCIに準拠したビルドまたは型検査を使う。モノレポ内の無関係な技術的負債まで表面化させる、非対応のルート全体型検査は実行しない。
- 依存関係のインストールは、ワークスペースにまだ導入されていない場合に限り、テストやビルドの前に行う。
- タスクで明示的に求められていない限り、開発サーバーや完全ビルドを開始しない。
検証は変更したパッケージとCIで使われる検査に合わせる。
## 書き方でなく、コードの動きをテストする
テストを作成または変更する前に、リポジトリのテストガイドを確認する。コアのバグ修正では、現実的な場合にレッド・グリーン・リファクタリングを用いる。まず失敗を再現し、次に最小限の修正を行い、その後で振る舞いを変えずに構造を改善する。
単体テストはソースファイルと同じ場所に置く。統合テスト、エンドツーエンドテスト、AI評価テストは、それぞれ指定されたテストツリーに置く。テスト対象が特にロガー境界でない限り、実際のログ実装を使う。
意味のある振る舞いの後退を検出できるテストを優先する。非公開の実装詳細を言い換えるだけの価値の低いアサーションは避ける。プロンプトやモデルの振る舞いを変更する場合は、通常のコードテストに加えて、意味に基づく評価または構造化契約のテストを用意する。
## 依存関係は、使っているワークスペースに入れる
依存関係はモノレポのルートではなく、それを使うワークスペースにインストールする。新しいワークスペースパッケージを追加する場合は、依存関係をインストールする前にパッケージ情報をコピーする、本番用およびローカル用のすべてのコンテナビルドマニフェストを更新する。
環境変数は、環境設定のサンプルファイル、実行時検証モジュール、モノレポのビルド構成の間で同期させる。ブラウザコードに公開する変数には、リポジトリ所定の公開変数プレフィックスを付ける。
バージョンに依存する、または不明確なフレームワークの振る舞いについては、コードを変更する前に、インストール済みの依存関係に同梱された文書を読む。記憶や、別のインストール済みバージョンを対象とする文書には頼らない。
## 定義しているファイルから直接インポートし、型はスキーマから作る
厳格なnull検査を使い、インターフェースを重複定義せず、検証スキーマからTypeScriptの型を推論する。定義したファイル内だけで使う型はエクスポートしない。
- すべてのインポートをファイルの先頭に置き、ファイル途中の動的インポートを追加しない。
- 再エクスポートの連鎖やバレルファイルを作らず、元のソースから直接インポートする。
- ユーティリティライブラリ全体ではなく、個々のユーティリティ関数をインポートする。
- アプリケーション内部のインポートには、設定済みのプロジェクトルート別名を使う。
- 補助関数はファイルの末尾に置く。
- APIルートファイル1つにつき、リソースは1つだけにする。
所有関係を直接的にすれば、依存関係、ツリーシェイキング、変更の影響を理解しやすくなる。
## 補助関数は、コードが読みやすくなる時だけ切り出す
既定では、ロジックを使用箇所に直接記述し、同じ場所に置く。小さな式の重複は、時期尚早な補助関数より明確な場合が多い。パラメーターの名前を変えて転送するだけの関数は切り出さない。
補助関数が意味のあるドメイン概念に名前を与える場合、周囲の制御フローを読みやすくする場合、または正確さが重要な振る舞いを複数のフローで一貫させる場合に切り出す。コピー間の同期がバグ回避に不可欠なら、実質的に重複するロジックは早い段階で一元化する。
大きな三項演算子や入れ子の三項演算子は避ける。素直な制御フロー、目的を絞った補助関数、または検索表を選ぶ。コメントには自明なコードが何をしているかではなく、その判断が存在する理由を書く。
読みやすさを保てる最も単純な変更を選ぶ。要件で求められる場合にだけ後方互換性を維持する。それ以外では、使われない移行経路を重ねず、連動する呼び出し箇所を直接更新する。
## 個人の情報を、広く見られるログに残さない
呼び出しチェーンの上位ですでに付与されたロガーのコンテキストフィールドを繰り返さない。送信者、受信者、メッセージ件名など個人を識別できるフィールドは、リポジトリで最も制限の厳しいトレースレベルにだけ記録する。
明確に文書化された例外によって、認証済みユーザー本人の識別子をより広いレベルで扱える場合がある。ただし、その例外を第三者のデータには拡張しない。プライバシーフィルター、コンテキストの伝播、フォーマット処理が引き続きテストされるよう、テストでは実際のロガーを使う。
ログを追加する前に、対象読者、保持期間、機密性、既存のコンテキストがその値をすでに提供しているかを確認する。
## UIの状態はデータから作り、共通のコンポーネントを使う
取得したpropsやサーバーデータを、effectを介してローカル状態へ複製しない。読み取り専用ビューには導出値を使い、ユーザーが操作する下書きには明示的な編集状態を使う。
独自の基本コンポーネントを作る前に、リポジトリで承認されたコンポーネントライブラリを使う。非同期コンテンツは共通の読み込み・エラー用ラッパーを通してレンダリングし、読み込み、失敗、成功の各状態を一貫させる。
ルート固有のページコンポーネントは、入れ子のコンポーネントディレクトリを追加せず、ルートのエントリファイルの隣に置く。複数ページで共有するコンポーネントは、アプリケーションの共有コンポーネントディレクトリに置く。
## データの変更は、サーバーアクションと共通の検証スキーマで行う
アクセスレベルに応じてルートミドルウェアを選ぶ。公開エラー処理、認証済みユーザーのアクセス、アカウント範囲のアクセスを区別する。レスポンス用インターフェースを重複定義せず、データ関数から導出してレスポンス型をエクスポートする。
Webの変更処理では、リポジトリの安全なアクション層を介してサーバーアクションを使う。POST APIルートは、ネイティブクライアントなど、安定した外部HTTP契約を必要とする統合のために確保する。
変更処理の検証スキーマは指定された検証モジュールで定義し、そのスキーマから入力型を推論する。読み取りには確立済みのクライアントキャッシュを使い、変更後に影響を受けるキーを無効化する。フォームは承認済みのフォームライブラリとアクションフックで構築し、失敗は共通のアクションエラーフォーマッターに渡す。
通常のアプリケーションロジックではプロバイダー抽象化を使う。具象プロバイダーの型を検査するのは、本当の統合境界に限る。リポジトリで禁止されている場合は、コールバック方式の動的データベーストランザクションを避ける。
## LLM機能は、キーワードの一覧でなく意味でテストする
1つの評価事例の文言ではなく、一般的なモデルの失敗パターンを修正する。モデルが現在使っている言い回しだけを検出する目的で、プロンプト、評価、テストにキーワードやフレーズのブラックリストを追加しない。文字列検査は言語をまたぐと特に壊れやすい。
モデルが不要な確認や根拠のない状態報告を避けているかなど、意味上の結果を判定基準または構造化契約で検証する。場当たり的なユーザーテキスト照合によって、コンテキスト注入やツールの振る舞いを制御しては絶対にいけない。構造化された状態、メタデータ、または明示的なイベントを使う。
すべてのツール説明は、目的、パラメーターの意味、選択指針、前提条件、ツール固有の安全制約を含み、それだけで理解できるようにする。システムプロンプトには、横断的なアイデンティティ、確認、セキュリティ、フォーマットの方針だけを置き、ツールごとの指針はツール説明に置く。
## 差分を見直し、実行したチェックを報告する
完了を報告する前に変更差分を確認し、影響を受ける振る舞いを証明する最小限のCI準拠検査を実行する。契約が統合や評価の境界をまたぐ場合は、統合テストまたは評価テストまで範囲を広げる。
次を確認する。
- すべての依存関係と環境変数を、正しいワークスペースが所有している。
- テストが振る舞いを網羅し、新しいテストファイルを検出できる。
- インポート、スキーマ由来の型、補助関数、抽象化がリポジトリの規約に従っている。
- ログによって個人データの露出範囲が広がっていない。
- UI状態、変更処理、検証、キャッシュ無効化、読み込み状態が確立済みのパターンに従っている。
- LLMの振る舞いが、壊れやすい文言ではなく意味に基づいてテストされている。
- 非対応のルート全体検査、開発サーバー、完全ビルドを、承認なしに実行していない。
実行した検査と、意図的に対象外とした広範な検査を報告する。
