検索/ロボットとAI向けのRust製データフロー基盤を、変更ごとに合うテストで開発する

ロボットとAI向けのRust製データフロー基盤を、変更ごとに合うテストで開発する

ロボットとAI向けの、Rust製データフロー基盤をAIに直させる時に使う。通信の決まりをはっきり保ち、コミットごとに検査を通し、危なさに合わせて深いテストを選び、どのテストを実際に流したかを報告する。

このAIルールを使うには
## Rustワークスペースを組み、ランタイムを4つの役割に分ける システムを、Python、C、C++向けバインディングを備えたRustワークスペースとして構成する。最小ツールチェーンと共有パッケージのメタデータはワークスペースルートに置き、明示的に文書化されたクレートやサンプルだけが独立したバージョンを固定できるようにする。 責務が明確な4つのランタイム役割を使う。 - コマンドラインクライアントは、データフローのビルド、開始、停止、検査を行う。 - コーディネータは、複数マシンにまたがる分散ライフサイクルを管理する。 - 各マシンのデーモンはノードを起動し、ローカル通信とリモート通信を管理する。 - ノードはユーザーコードをプロセスとして実行し、オーバーヘッドを下げる必要がある場合はオペレータをプロセス内で実行する。 メッセージとプロトコルの定義は共有ライブラリに、ディスクリプタ解析とビルド補助機能はコアライブラリに、各言語APIは個別パッケージに置く。言語バインディングのビルド要件を、通常のRust専用ビルドへ混入させない。 ## 言語バインディングは、Rustワークスペースとは別にビルドする 別のパッケージングツールが必要な言語バインディング用パッケージを除外して、Rustワークスペースをビルドする。それらのパッケージを通常のワークスペースコマンドへ無理に通さず、対応するバインディング用ツールチェーンでビルドする。 反復作業には、ワークスペース全体、1つのパッケージ、1つのテスト対象という3段階を用意する。ワークスペースの正規コマンドでcheck、test、lint、formatを実行し、ローカルのコマンドラインツールは依存関係をロックして導入する。 lint、test、統合スナップショット、文書検査より先にビルドする。通常のワークスペースcheckではサンプル対象がコンパイルされない場合があるため、サンプルには明示的なcheckが必要になる。 反復中は短時間のパッケージテストを使ってよいが、公開前には影響を受けるワークスペース全体へ戻る。新しいサンプルデータフローを追加した場合は、対応言語モードでサンプル用スモークスイートを実行する。 ## 3つの通信の型と、共有メモリを使う決まりをはっきりさせる データフローは宣言的に定義する。ノードは名前付き出力を購読し、自身の出力を宣言する。タイマーソースを提供し、その周波数または間隔をディスクリプタへ明記する。 利用者向けの異なる3つの通信パターンを維持する。 - Topicは既定のpublish/subscribeフロー。 - Serviceはrequest/replyであり、`request_id`を通じてメッセージを対応付ける。 - Actionはgoal、feedback、result、cancellationを表し、`goal_id`と`goal_status`を使う。 内部イベントのルーティングには上限付きマルチプロデューサチャネルを使い、オーケストレーションにはasyncランタイムを使う。マシン間では分散publish/subscribe通信を使い、因果順序にはハイブリッド論理クロックを使う。 ローカルノードの通信では、4 KBを超えるメッセージをゼロコピー共有メモリで送り、それ以下のメッセージをTCPで送る。しきい値、所有権、フォールバック動作を明示し、ローカル共有メモリとリモートネットワークの意味を、文書化されていない1つの経路へ統合してはならない。 ## コミットごとに、レビューと簡素化をしてからテストを通す すべてのコミットは、公開前に次のゲートを完了しなければならない。 1. 差分に構造、セキュリティ、ロジックの欠陥がないかレビューする。 2. 不要な複雑さ、重複、非効率を簡素化する。 3. formatを確認し、警告をエラーとしてlintし、少なくとも影響を受けるパッケージのtestを実行し、公開前にはワークスペース全体をtestする。 4. 通常のワークスペースグラフ外にAPIシグネチャの破損が隠れないよう、サンプル対象をコンパイルする。 各コミット前に、format、lint、依存関係監査、危険な近道の使用量、誤字検査を含む高速なローカルゲートを使う。その後、公開前に必須の全testコマンドを実行する。 失敗したゲートを飛ばしたり、低速なリモートCIが検出することに頼ったりしてはならない。失敗を修正し、影響を受けたゲートを再実行する。順序を維持する。広いtestより先にレビューと簡素化を行えば、設計上の欠陥を低コストで修正できる。 ## 時間のかかる深いテストは、毎回ではなく変更の危なさで選ぶ すべてのコミットで全詳細スイートを実行したり、その全部をプルリクエストCIへ追加したりしてはならない。変更範囲に応じて選ぶ。 - 追加の確信が必要な重要な公開前には、カバレッジを含む完全なローカルスイートを使う。 - 高リスクまたはTier 1の変更には、ミューテーションと互換性分析を含む詳細検証を使う。 - クロスプラットフォーム、プロパティ、インタプリタ、形式証明、エンドツーエンドのカバレッジには、数時間かかるnightly相当検証を使う。 - 配布前にはリリースゲートを使い、独立したセキュリティレビュー、実利用試験、移行検証は人間主導の別ゲートとして維持する。 - リポジトリ全体のミューテーション監査は10〜18時間かかる可能性があるため、リリース水準のテスト評価または対象を絞った調査だけに使う。 - ノードAPI、コマンド動作、ディスクリプタを変更した後は、サンプルデータフローをエンドツーエンドで実行する。 - 証明対象モジュールを変更する時は形式証明を実行し、プロファイルは移植できないため、対象OSとアーキテクチャ上でプロファイル誘導最適化を実行する。 カバレッジ、ミューテーション、互換性、サンプル、形式検証、性能プロファイリングは、置き換え可能な代用品ではなく、相互補完する証拠として扱う。 ## プルリクエストのCIは速く保ち、長いジョブは夜に回す プルリクエストCIは、迅速でブロッキングなフィードバックを返せる規模に保つ。format、警告をエラーとするlint、コアtest、エンドツーエンドの障害経路、意味契約、ベンチマーク回帰、誤字、サプライチェーン、危険な近道の使用量、ライセンスを検査する。 数時間かかるジョブでブロッキングパイプラインを拡大してはならない。広範な検証は別にスケジュールする。 - Linux、macOS、Windowsでプラットフォームtestを実行する。 - サンプル、コマンドラインテンプレート、動的言語ノード、ベンチマーク、クロスコンパイルを検査する。 - 分散ライフサイクル、record/replay、再接続、状態再構築、CPU affinity、ストレージバックエンド、ブリッジアダプタを対象にする。 - 最小対応コンパイラと形式証明ハーネスを確認する。 nightlyの失敗は追跡可能な回帰シグナルを作るべきだが、無関係なプルリクエストをブロックする必要はない。変更が既定外のプラットフォームまたはサンプル経路に依存する場合、マージ前にそのローカル検査を実行する。 ## 先に失敗するテストを書き、それを通すだけのコードを書く すべての新機能とバグ修正はRED-GREEN-IMPROVEに従う。 1. RED:期待する動作を定義する最小のtestを書き、意図した理由で失敗することを確認する。 2. GREEN:そのtestを通すために必要な最小限のコードだけを実装する。 3. IMPROVE:対象を絞ったtestと影響を受けるパッケージのtestを成功状態に保ちながらリファクタリングする。 動作に応じて最初のtest階層を選ぶ。ライブラリ関数は単体test、コーディネータまたはデーモンの動作は統合test、コマンド変更はネットワーク型スモークtest、データフロー機能はネットワーク型とローカル型の両方のスモークtest、バグ修正は欠陥を再現する最小範囲の回帰testから始める。 対象を絞ったtestが通った後、影響を受けるパッケージ、警告をエラーとするlint、formatの検査を実行する。変更がコマンドクライアント、コーディネータ、デーモンに触れる場合、共有ポートまたは共有プロセスの分離が必要な箇所では、スモークtestも直列実行する。 ## サンプルのデータフローを、ネットワーク型とローカル型の両方で試す 2つのスモークモードを提供する。 - ネットワーク型モードは、分散ランタイムを開始し、データフローを分離実行し、完了までポーリングしてから、ランタイムを停止して終了処理を行う。 - ローカル型モードは、明示的な停止期限を設け、1つのプロセス内でデータフローを実行する。 新しいサンプルデータフローは両方のモードを通さなければならない。testごとに再ビルドせず、一度だけ実行するガードを通じて高コストなビルド準備を共有する。 コマンド通信と耐障害性のエンドツーエンドtestは、通常の単体testから分離する。後続testを汚染しないよう、スモークスイートは成功時と失敗時の両方でプロセスとポートを後片付けしなければならない。 利用できないハードウェア、対話入力、複数マシン構成、非対応のネイティブツールチェーンを必要とするサンプルは、既定のスモーク対象から外してよい。ただし、対象外となる境界を文書化し、それらを個別実行する方法を用意する。 ## 変更を小さく保ち、実際に通した検査をそのまま報告する 変更を提出する前に、リポジトリ既定のフォーマッタで整形する。非自明な設計変更は、実装前にプロジェクトの意思決定チャネルで議論する。 同じ変更で無関係な警告を修正したり、無関係なコードをリファクタリングしたりしてはならない。失敗、レビュー、ロールバックの原因を追跡できるよう、パッチ範囲を限定する。 言語パッケージとコマンドラインバイナリを別々の配布対象として扱う。それぞれに適切なパッケージ、バインディング、互換性、リリースの検査を行う。 正しさのゲートが通った後だけ、最適化したリリースプロファイルを使う。性能作業では対象プラットフォームを報告し、再現可能な基準値と最適化ビルドを比較しなければならない。 引き渡し前に、高速、完全、詳細、nightly、サンプル、証明、性能のうち、実際に実行したゲートと未検証のゲートを報告する。1つの階層が成功しただけで、別の階層も通ったと示唆してはならない。