From 4258cf5f1a2c51435f99df49e063d8a693a4248b Mon Sep 17 00:00:00 2001 From: "Teppei.F" <37261985+T3pp31@users.noreply.github.com> Date: Sat, 30 May 2026 11:24:28 +0900 Subject: [PATCH 1/2] chore: track rust-coding and rust-testing Cursor rules in git These rules were local-only and were dropped when switching to main (GitHub Desktop stashed untracked files). Align with .gitignore policy for .cursor/rules/*.mdc. Co-authored-by: Cursor --- .cursor/rules/rust-coding.mdc | 138 +++++++++++++++++++++++++++++++++ .cursor/rules/rust-testing.mdc | 107 +++++++++++++++++++++++++ 2 files changed, 245 insertions(+) create mode 100644 .cursor/rules/rust-coding.mdc create mode 100644 .cursor/rules/rust-testing.mdc diff --git a/.cursor/rules/rust-coding.mdc b/.cursor/rules/rust-coding.mdc new file mode 100644 index 0000000..eaa51f8 --- /dev/null +++ b/.cursor/rules/rust-coding.mdc @@ -0,0 +1,138 @@ +--- +description: Rustコーディングルール(型・Result・所有権・clippy) +alwaysApply: false +globs: **/*.rs,**/Cargo.toml +--- + +# Rust コーディングルール + +既存の Cargo ワークスペース・クレート構成に従うこと。本ルールは新規実装・リファクタ時の共通方針とする。 + +## プロジェクト構造 + +- `Cargo.toml` / `Cargo.lock` の既存パターン(workspace、features、dependencies)を崩さない。 +- バイナリとライブラリを分ける場合は、再利用ロジックは `lib` に置き、`main.rs` は薄く保つ。 +- 1モジュールが肥大化したら、責務単位で `mod` 分割し、`mod.rs` または `foo.rs` + `foo/` ディレクトリに整理する。 + +### 責務の分離 + +| 層 | 責務 | +|---|---| +| `domain` / `model` | 型・不変条件・純粋な変換 | +| `service` / `use_case` | ビジネスロジックの組み立て | +| `infra` / `adapter` | DB・HTTP・ファイル I/O など外部境界 | +| `api` / `cli` | 入出力の変換・ルーティング | + +下位層(domain)が上位層(api)に依存しないこと。循環依存は禁止。 + +--- + +## エラー処理 + +- ライブラリクレートでは `Result` を返し、**本番コードで `unwrap()` / `expect()` を使わない**(プロトタイプ・テスト・`main` の起動失敗メッセージ等、既存慣習がある場合は除く)。 +- エラー型は `thiserror` またはプロジェクト既存の方式に合わせる。アプリケーション境界では `anyhow` 可(既採用時のみ)。 +- `panic!` は回復不能なバグ用に限定し、入力検証失敗は `Result` で表現する。 +- `?` を優先し、不要な `match` のネストを避ける。 + +--- + +## 型指定(必須) + +**新規・変更する Rust コードは、型で意図を表現する。** コンパイラ推論に任せきりにせず、公開 API とドメイン境界は明示的な型にする。 + +### 付与・明示の範囲 + +| 対象 | 要件 | +|------|------| +| `pub fn` / `pub struct` / `pub enum` | シグネチャ・フィールド型を明示。`///` ドキュメントを付ける | +| 関数の引数・戻り値 | 推論任せにせず、公開・再export される API は型を読み取れるように書く | +| エラー | 成功は `T`、失敗は `E`。`Result` を返し、意味のあるエラー型を定義する | +| オプション | 「無いかもしれない」は `Option`。「失敗しうる」は `Result`。混同しない | +| 定数 | マジックナンバーは `const` / `enum` / `newtype` で名付ける | +| 内部コード | 推論で十分なら省略可。ただし複雑な式・ジェネリクス・`collect()` 前後は型を明示 | + +### 設計の書き方 + +- **不正な状態を型で表現**する。フラグの組み合わせより `enum`、ID の混同防止に `struct UserId(u64)` 等の newtype。 +- **所有権を型で表現**する。借用で足りる引数は `&str` / `&[T]`。所有権が必要なときだけ `String` / `Vec`。 +- 列挙で分岐が閉じるようにし、`match` は網羅的に(`#[must_use]` を適宜付与)。 +- コレクション変換は型をはっきりさせる。例: `let items: Vec = iter.collect()`(空の `collect()` 任せを避ける)。 +- トレイト境界は必要最小限。公開 API が複雑になる場合は `impl Trait` や具体的な型を優先し、過剰な `` を避ける。 +- 動的ディスパッチが必要なときだけ `dyn Trait`。可能なら `enum` またはジェネリクスで静的に解決する。 +- 非同期は `async fn foo() -> Result` のように戻り値を明示。`Future` を無名で返すだけにしない。 + +### 禁止・抑制 + +- 本番のライブラリコードで `unwrap()` / `expect()` に頼って型・エラーをごまかさない(テスト・`main` の起動処理は除く)。 +- `panic!` で入力検証を済ませない。検証失敗は `Result` / `Option`。 +- `todo!()` / `unimplemented!()` を本番パスに残さない。 +- `as` キャストは理由がない限り使わない。`TryFrom` / `From` を検討する。 +- `clone()` で所有権問題を回避する前に、借用・ライフタイム・データ構造の見直しをする。 + +### 検証 + +- 変更後は `cargo check` を必ず実行する。 +- プロジェクトで `cargo clippy` / `cargo clippy -- -D warnings` がある場合は警告を解消する。 +- `cargo test` で型・API 変更に伴うテスト破壊がないことを確認する。 + +### 例 + +```rust +// ❌ エラーを unwrap で握りつぶす +pub fn load_config(path: &str) -> Settings { + let data = std::fs::read_to_string(path).unwrap(); + toml::from_str(&data).unwrap() +} + +// ✅ 型で失敗を表現 +pub fn load_config(path: &str) -> Result { + let data = std::fs::read_to_string(path)?; + let settings: Settings = toml::from_str(&data)?; + Ok(settings) +} + +// ❌ プリミティブの積み上げ +fn set_status(user_id: u64, status: u8) { ... } + +// ✅ 意味のある型 +struct UserId(u64); +enum UserStatus { Active, Suspended } + +fn set_status(user_id: UserId, status: UserStatus) { ... } +``` + +### 公開 API ドキュメント + +- `pub` 項目には `///` を付け、**エラー条件**(`Result::Err` の意味)、**パニック条件**(パニックする場合のみ)、**不変条件**を書く。 +- 型パラメータ・ライフタイムが非自明なら、使用例を1行でもよいので doc コメントに含める。 + +--- + +## 実装スタイル + +- `rustfmt` のフォーマットに従う。変更後は `cargo fmt` を実行する。 +- `clippy` の警告を無視せず、既存の `#[allow(...)]` ポリシーに合わせる。 +- `unsafe` は既存コードに必要な場合のみ。新規では避け、使う場合は安全性の根拠をコメントする。 +- 非同期(`async`)はプロジェクトで既に採用されているランタイム(tokio 等)に合わせる。ブロッキング I/O を async 内に混ぜない。 +- ログは `tracing` / `log` 等、プロジェクト既存のクレートを使う。`println!` デバッグ残しは避ける。 + +--- + +## 依存関係・設定 + +- 新規 crate 追加は理由を明示し、既存クレートで代替できないか確認する。 +- 機能フラグ(`[features]`)でオプション機能を切り離す(既存パターンがある場合)。 +- 環境依存の値(URL、しきい値、パス)はソースに直書きせず、設定ファイルまたは環境変数で読み込む。 + +--- + +## テストとの関係 + +- テストの書き方は `rules/testing/` および `rust-testing` ルールに従う。 +- テスト内の `unwrap()` は可。本番コードの設計をテスト都合で劣化させない。 + +## 変更時の確認 + +- `cargo check` / `cargo build` / `cargo test` を実行し、失敗がないことを確認する。 +- 公開 API(型・トレイト・エラー型)を変えた場合は、呼び出し元・テストをあわせて更新する。 +- 既存の期待動作を壊さないこと。挙動変更は意図をコメントまたは changelog に残す。 diff --git a/.cursor/rules/rust-testing.mdc b/.cursor/rules/rust-testing.mdc new file mode 100644 index 0000000..eb053b9 --- /dev/null +++ b/.cursor/rules/rust-testing.mdc @@ -0,0 +1,107 @@ +--- +description: テスト作成ルール・Rust(等価分割・境界値・Given-When-Then) +alwaysApply: false +globs: **/*.rs,**/tests/** +--- + +# テスト作成ルール(共通) + +テストコードの新規作成・追加・修正時は、言語固有ルールとあわせて本セクションを適用する。 + +## 1. 事前確認 + +- テストが必要かどうか不明な場合は、**AskUserQuestion** で確認すること。 +- 着手前に以下を把握すること: + - 言語・ランタイム + - テストフレームワーク(プロジェクト既存のものを優先) + - 既存のテストディレクトリ・命名規則・フィクスチャの置き場所 + +## 2. 必須プロセス + +1. **テスト観点の表**(等価分割・境界値)を Markdown 表で**先に**提示する。 +2. 表に基づいてテストコードを実装する。 +3. **失敗系を正常系と同数以上**含める。 +4. 以下を必ず網羅する: + - **正常系** — 主要シナリオ・代表入力 + - **異常系** — バリデーション失敗・エラー返却・例外 + - **境界値** — 0、最小、最大、±1、空、NULL / `None`、空コレクション + - **不正入力** — 型・形式・範囲の不正さ + - **外部依存の失敗** — 該当する場合(モック・フェイクの前提を明示) + - **エラー内容の検証** — 例外種別・エラーメッセージ・エラーコード +5. 各テストケースに **Given / When / Then** 形式のコメントを付ける。 +6. 回答末尾に **実行コマンド** と **カバレッジ取得方法** を記載する。 +7. **目標: 分岐網羅 100%**(不足観点は実装前に表へ追記する)。 + +## 3. 変更時の必須確認 + +- コード修正を行ったら、**必ず**テストを実行して結果を確認する。 +- 既存テストが落ちないこと。仕様変更はテストとドキュメントを同時に更新する。 +- フレークのないテストにする(時刻・乱数・並列は固定シード・モックで制御)。 + + +--- + +# テスト作成ルール(Rust) + +上記「テスト作成ルール(共通)」に加え、Rust プロジェクトでは以下を適用する。 + +## 4. テストの種類と配置 + +| 種類 | 置き場所 | 用途 | +|---|---|---| +| ユニットテスト | 対象 `.rs` 内の `#[cfg(test)] mod tests` | 純粋関数・小さなモジュール | +| 統合テスト | クレート直下 `tests/*.rs` | 公開 API・複数モジュールの連携 | +| ドキュメントテスト | `///` コードブロック | 使用例・仕様の固定 | + +- 新規統合テストは `tests/` に **1 ファイル 1 テーマ**で追加する(`tests/foo.rs`)。 +- テスト専用ヘルパーは `tests/common/mod.rs` または `#[cfg(test)]` に置く。 +- 既存の `proptest` 等があれば、その構成を優先する。 + +## 5. 実装の書き方 + +- アサーションは `assert!` / `assert_eq!` / `assert_matches!` を使い、失敗時に期待値が分かるメッセージを付ける。 +- エラー系は `Result::Err`・`Option::None` を明示的に検証する。 +- パニック期待は `#[should_panic]` または `catch_unwind` を使い、理由をコメントする。 +- 非同期は `#[tokio::test]` 等、プロジェクト既存のマクロに合わせる。 +- `unwrap()` は **テストコード内のみ** 許容。本番コードに `unwrap` を増やしてテストしやすくしない。 + +### 例 + +```rust +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn parses_valid_hex() { + // Given: 32文字の16進文字列 + // When: parse_hex_input を呼ぶ + // Then: 16バイトの Vec が返る + let got = parse_hex_input("00112233445566778899aabbccddeeff").unwrap(); + assert_eq!(got.len(), 16); + } +} +``` + +## 6. 実行コマンドとカバレッジ + +回答末尾に以下を含めること。 + +```bash +# クレート全体 +cargo test + +# 特定テストのみ +cargo test parses_valid_hex + +# 統合テストのみ +cargo test --test integration_name +``` + +カバレッジ(`cargo-llvm-cov` 等がプロジェクトにあれば): + +```bash +cargo llvm-cov --html +``` + +ツール未導入時は、プロジェクトで採用している手段を確認してから記載する。 From d177bd6b451a4a8f30d13de0c9838ea4256c14f5 Mon Sep 17 00:00:00 2001 From: "Teppei.F" <37261985+T3pp31@users.noreply.github.com> Date: Sat, 30 May 2026 11:25:03 +0900 Subject: [PATCH 2/2] chore: share Cursor rules and AGENTS.md in the repository - Stop gitignoring .cursor/rules and AGENTS.md - Only ignore .cursor/plans/ (local plan cache) Co-authored-by: Cursor --- .gitignore | 9 ++--- AGENTS.md | 105 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 108 insertions(+), 6 deletions(-) create mode 100644 AGENTS.md diff --git a/.gitignore b/.gitignore index 6123b7b..a1f1320 100644 --- a/.gitignore +++ b/.gitignore @@ -1,9 +1,6 @@ target .DS_Store -# Cursor / エージェント(ローカルのみ) -.cursor/* -!.cursor/rules/ -.cursor/rules/* -!.cursor/rules/*.mdc -AGENTS.md +# Cursor: ルール・エージェント設定はリポジトリで共有(.cursor/rules/, AGENTS.md) +# ローカル専用のプラン・キャッシュのみ除外 +.cursor/plans/ diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..33e285a --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,105 @@ + +# Agent Configuration + +## 基本方針 + +- 回答・説明・進捗報告は必ず日本語で行うこと。 +- 実装・設計・調査は必ず Task ツールを使って進めること。 +- subagent は常に親モデルを継承すること。 + - Task ツール呼び出し時に `model` パラメータを指定してはならない。 +- 不明点がある場合は、推測で進めず AskUserQuestion を使って質問すること。 +- 既存の期待動作を壊さないことを最優先すること。 + +## Plan モード時のルール + +Plan モードでは、実装前に必ず以下を明示すること。 + +- 作業目的 +- 影響範囲 +- 使用する subagent +- 各 subagent に担当させる内容 +- 修正予定ファイル +- 確認・テスト方針 +- 不明点がある場合は AskUserQuestion で確認すること + +設計作業は必ず subagent に Task として依頼すること。 + +## 開発時のルール + +開発作業は必ず subagent に Task として依頼すること。 + +Task 作成時は以下を明確にすること。 + +- 目的 +- 対象ファイル +- 変更方針 +- 期待される挙動 +- 既存挙動への影響確認 +- 実施すべきテストまたは確認方法 + +subagent を使う際、`model` パラメータは指定しないこと。 + +## 実装方針 + +実装は、目的を満たすために必要な最小限の機能に留めること。 + +- 要求されていない機能を追加しないこと。 +- 将来使うかもしれないという理由だけで実装を増やさないこと。 +- 既存の設計や実装方針に沿って、変更範囲を最小限にすること。 +- 過剰な抽象化、過剰な汎用化、不要なリファクタリングを避けること。 +- ただし、可読性・保守性・テスト容易性が向上する場合は適切に関数化すること。 + +関数化する際は、以下を意識すること。 + +- 1つの関数は1つの責務に集中させること。 +- 複雑な条件分岐や重複処理は関数として切り出すこと。 +- 関数名から処理内容が分かるようにすること。 +- 呼び出し元の可読性が下がるような過度な分割は避けること。 +- 既存の関数やユーティリティで代用できる場合は新規作成しないこと。 + +## 設定ファイル + +環境依存の値・しきい値・URL・機能フラグなどは、ソースコードに直接書かず **別ファイルの設定** として管理すること。 + +- 定数や設定値をプログラム内にハードコードしないこと。 +- プロジェクトの慣習に合わせ、設定用ファイル(例: `.env`、`config.yaml`、`settings.toml`、フレームワークの設定ディレクトリ)を作成し、そこにまとめること。 +- 既存の設定ファイルや読み込み処理がある場合は、それを拡張すること。同目的の設定ファイルを重複して作らないこと。 +- シークレット(API キー、トークン、パスワード)はリポジトリにコミットせず、環境変数やローカル専用ファイル(`.env.local` 等)で扱うこと。 +- 新規に設定ファイルを追加する場合は、配置場所・読み込み方法・必須項目をコード変更とあわせて明示すること。 + +## Web 検索のルール + +以下の場合は web 検索を行うこと。 + +- 技術的に詰まった場合 +- 原因不明のエラーが解決できない場合 +- 使用しているライブラリ、API、フレームワークの仕様に不確実性がある場合 +- 最新の仕様や既知の不具合を確認する必要がある場合 + +検索時は、可能な限り以下を優先すること。 + +- 公式ドキュメント +- 公式リポジトリ +- Issue / Discussion +- 信頼できる技術記事 + +検索結果を利用した場合は、何を根拠に判断したかを簡潔に説明すること。 + +## 修正前の確認 + +ファイルを修正する前に、必ず以下を提示すること。 + +- 現在のディレクトリ構造 +- 修正対象ファイル +- 各ファイルを修正する理由 + +例: + +```text +. +├── src/ +│ ├── components/ +│ │ └── Button.tsx # 表示ロジックの修正対象 +│ └── utils/ +│ └── format.ts # 既存処理への影響確認対象 +└── package.json # テストコマンド確認対象