# pytest 標準テンポラリ機能移行プラン

## ゴール
- pytest 標準の一時ディレクトリ API（`tmp_path` / `tmp_path_factory` 等）へ統一し、手動管理パスを廃止する。
- テスト実行後に環境に残骸が残らない状態を保証し、CI とローカルの結果差異を減らす。
- 影響範囲を段階的に縮めながら安全に移行し、既存テストの保守性を高める。

## 準備
- `pyproject.toml`（または `pytest.ini`）の `addopts` とプラグイン設定を棚卸しし、既存の `--basetemp`／`--rootdir` 指定やカスタムプラグインを把握する。
- `tests/` 配下の `conftest.py`／フィクスチャツリー／`pytest_sessionstart` などのフックを読み解き、テンポラリディレクトリ使用箇所をマップ化する。
- `temp/`、`var/`、`out/` など手動クリーンアップ前提のディレクトリを列挙し、削除時の影響範囲を確認する。
- 既存ドキュメント（`docs/guides/pytest_test_data_policy.md` 等）と照らし合わせ、整合性の取れていない運用ルールを整理する。

## ステータスサマリ（2025-10-23 更新）
| フェーズ | 状況 | 主要完了項目 | 次のアクション |
|----------|------|--------------|----------------|
| フェーズ 1 | ✅ 完了 | 固定パス棚卸し資料と `tests/conftest_cleanup_analysis.md` の共有、テンプレート公開 | テンプレート活用状況を定期レビューし、フェーズ 2/3 の進行記録を継続更新 |
| フェーズ 2 | 🔄 進行中 | `tests/conftest.py` に `test_data_dir` / `temp_dir_factory` を整備し、`_route_tempfile_mkdtemp` でグローバルリダイレクトを実装 | 21 ファイル / 32 callsite の `tempfile.mkdtemp` を pytest フィクスチャへ置換し、スイート別の移行ガイドを整備 |
| フェーズ 3 | 🔄 進行中 | `_noveler_safe_getbasetemp` で basetemp を安定化し、`pytest_sessionfinish` から `TestCleanupManager` を自動呼び出し | `pytest_sessionstart` の手動ディレクトリ初期化ロジックを標準 API ベースへ簡素化し、ログ出力レベルをガイドに合わせる |
| フェーズ 4 | ⏸ 未着手 | `TestCleanupManager` は現状維持（セッション終了時に実行） | pytest 標準フィクスチャへ完全移行後にマネージャ撤去とドキュメント更新を段階的に実施 |

## フェーズ 1: 現状把握（現行資産の棚卸し）
**目的**
- テストが依存するテンポラリパスとクリーンアップ手順を可視化し、移行漏れを防ぐ。

**作業項目**
- `rg "temp" tests` などで固定パス参照を列挙し、分類（テスト、フィクスチャ、実コード）する。
- 現行の手動マネージャ（context manager、独自クラス、pytest フィクスチャ）を洗い出し、利用頻度と責務を整理する。
- CI で実行されるジョブ（`bin/test`、`make test` 等）の後処理ロジックをレビューし、残骸検知の仕組みと依存を記録する。

**完了条件**
- 固定パス参照一覧と依存図が作成され、所有チームと共有済み。
- 手動クリーンアップを要求するテストケース／ユーティリティがリスト化され、移行優先度が付与されている。

### 現状（2025-10-23 更新）
- ✅ `tests/conftest_cleanup_analysis.md`（2025-10-10 作成）で残骸発生パターンと恒久対策案を整理し、テンプレートを本ガイドへ統合済み。
- ✅ 固定パス棚卸しテンプレート／優先度マトリクスをドキュメント化し、ワーキンググループへの共有を完了。
- 🔄 `tempfile.mkdtemp` の直接利用は 22 ファイル / 33 callsite で存続（tests / src / scripts 配下）。対象一覧はフェーズ 1 棚卸し進捗テーブルに反映した。

## フェーズ 2: フィクスチャ改修（pytest 標準 API への置き換え）
**目的**
- テストごとのテンポラリパス確保を pytest 標準のフィクスチャに集約し、手動生成コードを削減する。

**作業項目**
- `tmp_path_factory.mktemp` を利用した `test_data_dir`（関数スコープ）と `session_tmp_dir`（セッションスコープ）等のフィクスチャを整備し、共通利用 API を定義する。
- 既存の独自ヘルパー／`Path(temp_dir)/...` を段階的に置き換え、テストコードでの直接パス結合を排除する。
- プロダクションコードが固定パスに依存するケースには、フィクスチャからパスを注入できるよう引数や `monkeypatch.setenv` を介した差し替えポイントを追加する。
- スイート固有のディレクトリ（例: `b20_test_project`）はフィクスチャ内で生成し、固定パス依存一覧テンプレートに記録して共有する。
- 各置き換え単位でテストを実行し、差分を最小限に保ちながら PR を分割する。

**完了条件**
- 主要テスト群が pytest の temp フィクスチャで動作し、手動生成ディレクトリを参照しない。
- 新設フィクスチャの利用方法がドキュメント化され、既存コード規約に組み込まれている。

### 現状（2025-10-23 更新）
- ✅ `tests/conftest.py` に `test_data_dir` / `temp_dir_factory` を実装し、pytest 標準 API への移行口を提供。
- ✅ 同ファイルのセッションスコープフィクスチャ `_route_tempfile_mkdtemp` により、`dir` 未指定の `tempfile.mkdtemp` 呼び出しを `tmp_path_factory.getbasetemp()` 配下へ自動ルーティング。
- ✅ `/test tests/unit/use_cases/test_b20_pre_implementation_check_use_case_simple.py tests/unit/infrastructure/commands/test_global_command_installer.py` を 2025-10-23 22:37 (JST) に実行し、クリーンアップログで残骸ゼロを確認。
- ✅ `tests/e2e/conftest.py` の `create_isolated_temp_dir` を `tmp_path_factory.mktemp` ベースへ移行し、E2E セッション環境も pytest 管理下の一時ディレクトリを利用。
- 🔄 integration / e2e / performance / domain サービス系テストなど 15 テストファイルで `tempfile.mkdtemp` を直接利用（合計 26 callsite）。フィクスチャ差し替え計画をスイート単位で策定する。
- 🔄 プロダクションコード 4 ファイルおよびサポートスクリプト 2 本でも `tempfile.mkdtemp` を使用中。設定注入や `tmp_path_factory` 連携インターフェースを設計する必要がある。

## フェーズ 3: フック簡素化（session フックのリデザイン）
**目的**
- `pytest_sessionstart`／`pytest_sessionfinish` 等で行っている手動初期化・後始末を、pytest 標準のライフサイクルに沿ったシンプルな実装へ置き換える。

**作業項目**
- フィクスチャ移行により不要となった初期化処理（`os.makedirs`、`shutil.rmtree` 等）を削除し、残すべき検証のみを抽出する。
- `tmp_path_factory.getbasetemp()` を利用し、必要な場合はベースディレクトリの状態チェックを行う簡潔なヘルパーを実装する。
- ロギング方針（`docs/guides/logging_guidelines.md`）に沿って、残骸検知や例外ハンドリングの出力レベルを調整する。
- CI とローカル双方でフック変更後の挙動を検証し、フックの責務がコメント／ドキュメントで明記されていることを確認する。

**完了条件**
- フック内に手動ディレクトリ操作が残っていない。
- セッション終了時の検証が冪等に成功し、不要な警告や失敗が発生しない。

### 現状（2025-10-23 更新）
- ✅ `TempPathFactory.getbasetemp` を `_noveler_safe_getbasetemp` でラップし、Windows / xdist 併用時の PermissionError を回避。
- ✅ `pytest_sessionfinish` で `get_cleanup_manager().cleanup_test_artifacts(dry_run=False)` を呼び出し、2025-10-23 実行ログでも残骸ゼロを確認。
- 🔄 `pytest_sessionstart` が `TEST_DATA_ROOT` を `shutil.rmtree` で初期化しており、pytest 標準のテンポラリ提供へ段階的に移行する必要がある。
- 🔄 `LLM_FAST_CLEANUP` フラグやエラーハンドリングのログレベル調整がガイドライン未反映。ドキュメント更新と運用フロー整備が未完。

## フェーズ 4: 手動マネージャ廃止（クリーンアップ責務の削除）
**目的**
- 独自のテンポラリマネージャ／コンテキストを撤去し、pytest 標準機能のみでクリーンアップが完結する状態へ移行する。

**作業項目**
- フェーズ 2 で利用実績がなくなった手動マネージャを段階的に削除し、互換ラッパーが必要な場合は pytest フィクスチャとして再実装する。
- `tests/utils/` 等に残るクリーンアップユーティリティを棚卸しし、削除または `tmp_path` 系 API への委譲に置き換える。
- ドキュメント・開発者ガイド（`docs/guides/developer_guide.md` など）を更新し、新しい運用ルールを反映する。
- CI／ローカルのテスト実行ログをモニタリングし、残骸に関するアラートがゼロであることを確認する。
- 旧 5 段階フォールバック経路を撤去し、21 段階テンプレートを必須経路として維持する。

**完了条件**
- 手動でテンポラリディレクトリを生成・削除するコードがリポジトリから撤廃されている。
- pytest 標準機能のみでテンポラリ管理が完結し、運用ドキュメントが更新済み。

### 現状（2025-10-23 更新）
- ✅ `noveler.infrastructure.shared.test_cleanup_manager.TestCleanupManager` はセッション終了フックから自動起動するが、pytest 標準 API へ置き換わっておらずフェーズ継続中。
- 🔄 `tests/conftest.py` の `get_cleanup_manager` フォールバックや `_assert_test_data_clean` が手動ロジックに依存しており、pytest のスコープ管理で代替する設計検討が必要。
- ⏸ マネージャ撤去後の残骸検知／ロールバック手順（SRE 連携）が未整備。フェーズ 2/3 完了後に改めてロードマップ化する。

## リスクと緩和策
- **テスト失敗時の一時ファイル残存**：フック簡素化前に既存の残骸検知が一時的に弱まる可能性があるため、フェーズ 2 完了までは旧ロジックを併存させ、CI での `/test-failed` モードを併用する。
- **プロダクションコードの固定パス依存**：移行中に `tmp_path` へ置き換えできないケースが露見する恐れがあるため、フェーズ 1 で依存度評価を行い、代替注入インターフェースの設計を事前に着手する。
- **ドキュメントと実装の乖離**：ガイド更新が後回しになると運用ミスにつながるため、フェーズ 4 の各削除 PR にドキュメント更新をバンドルし、レビュー項目に「docs 更新」を必須化する。

## コミュニケーションとステークホルダー連携
- QA / SRE / CI オーナーを含むワーキンググループを設置し、フェーズ移行の開始・完了を Slack チャンネルで告知する。
- 週次で棚卸しステータスを共有し、影響のあるテスト所有者へ移行スケジュールをフィードバックする。
- 重大な変更（フック削除、マネージャ撤去）はリリースノートに記載し、ロールバック手順を合わせて周知する。
- `/test-changed` レポートの結果と `reports/llm_summary.*` を共有ストレージにアップロードし、透明性を確保する。

## 成果物チェックリスト
- フェーズ 1：固定パス依存一覧表、残骸検知の現状レポート、移行優先度マトリクス。
- フェーズ 2：新フィクスチャの利用ガイド、`tmp_path` 移行済みテスト一覧、差分テスト結果。
- フェーズ 3：更新後の `conftest.py` 設計ノート、ログ設定差分、CI / ローカル検証ログ。
- フェーズ 4：削除済み手動マネージャの一覧、ドキュメント更新 diff、残骸監視メトリクスの安定化報告。

## フェーズ 1 棚卸し成果物テンプレート
**使い方のヒント**
- セクションごとにコピーし、各チームの作業スペース（Notion / Confluence / Git レポジトリ内 doc 等）へ貼り付けて編集する。
- テンプレート記入後は `/test-changed --range <branch>` の結果と合わせて共有し、差分確認を容易にする。

### 固定パス依存一覧テンプレート
````markdown
### 固定パス依存一覧
- 更新日: YYYY-MM-DD
- 担当: @owner
- 調査範囲: tests/, src/, tools/ など

| ID | ファイル/位置 | 種別 (テスト/フィクスチャ/実コード) | 現行処理 | 置換案 (`tmp_path` など) | 優先度 (H/M/L) | 備考 |
|----|---------------|-------------------------------------|----------|-------------------------|----------------|------|
| 1  | tests/...     | テスト                              | `temp/test_data/...` | `test_data_dir / "..."` | H |  |
| 2  | ...           | ...                                 | ...      | ...                     | ...            | ...  |
```` 

### 残骸検知現状レポートテンプレート
````markdown
### 残骸検知現状レポート
- 実行日: YYYY-MM-DD
- コマンド: `/test` / `/test-failed` / `make test`
- ブランチ / コミット: <branch-or-sha>

#### 概要
- 期待結果: `temp/test_data` が空で終了する 等
- 実測結果: 成功 / 失敗（残骸サイズ、件数）

#### 詳細ログ
```
（抜粋: LLM summary, ログファイルパス, 重要メッセージ）
```

#### フォローアップ
- 対応責任者: @owner
- 次回確認予定: YYYY-MM-DD
- メモ: 仮対処 / 恒久対処 の状況
```` 

### 移行優先度マトリクステンプレート
````markdown
### 移行優先度マトリクス
- 更新日: YYYY-MM-DD
- 担当: @owner

| パス依存 ID | 影響範囲 (大/中/小) | 技術的難度 (高/中/低) | 推奨フェーズ内完了目標 | ブロッカー | 対応状況 (未着手/進行中/完了) |
|-------------|---------------------|-----------------------|------------------------|------------|--------------------------------|
| 1           | 大                  | 中                    | フェーズ 2             | なし       | 未着手                         |
| 2           | 中                  | 高                    | フェーズ 3             | コンポーネント X 依存 | 進行中                |
````

## フェーズ 1 棚卸し進捗（2025-10-23 時点）
### 固定パス依存一覧（更新版）
| ID | ファイル/位置 | 種別 | 現行処理 | 置換案 / 対応状況 | 優先度 | 備考 |
|----|---------------|------|----------|--------------------|--------|------|
| 1  | tests/conftest.py:test_data_dir / temp_dir_factory | フィクスチャ | pytest tmp_path_factory に集約 | 実装済み（ユニット / ドメイン系テストで採用済み、他スイートは導入プラン策定中） | H | グローバルパッチは導入せず、段階的にフィクスチャへ移行 |
| 2  | tests/unit/hooks/test_halfwidth_checker.py | テスト | `tempfile.mkdtemp()` | `temp_dir_factory("halfwidth_case")` で置換済み | M | 個別フィクスチャのサンプル |
| 3  | tests/unit/tools/test_dependency_analyzer.py | テスト | setup/teardown で手動削除 | autouse フィクスチャ化済み | M | Analyzer 系のテンプレ構築に流用可能 |
| 4  | tests/integration/*・tests/e2e/*・tests/performance/* など 15 ファイル | テスト一式 | `tempfile.mkdtemp()` 直接呼び出し | 進行中（15 ファイル / 26 callsite をフィクスチャ差し替え予定） | H | `_route_tempfile_mkdtemp` で pytest basetemp 配下に集約。`tests/e2e/conftest.py` は tmp_path ベースへ移行済み、残りスイートの計画をレビュー中 |
| 5  | src/noveler/conftest.py 他 3 ファイル、scripts/* 2 本 | 実装 / スクリプト | `tempfile.mkdtemp()` | 未着手（設定注入・一時パス抽象化を設計） | M | プロダクションコードは設定注入で対応し、スクリプトは一時パス CLI オプション追加を検討 |

- 集計結果（2025-10-23）: tests 15 ファイル / 26 callsite、src 4 ファイル / 4 callsite、scripts 2 本 / 2 callsite。

### 残骸検知レポート（ショート版）
- 更新日: 2025-10-23
- コマンド: `/test tests/unit/use_cases/test_b20_pre_implementation_check_use_case_simple.py tests/unit/infrastructure/commands/test_global_command_installer.py`
- 結果: ✅ クリーンアップ対象なし（2025-10-23 22:37 JST 実行時、`TestCleanupManager` ログ上も Files=0 / Dirs=0 / Protected=1 を確認）

### 移行優先度マトリクス（更新版）
| パス依存 ID | 影響範囲 | 技術的難度 | 推奨完了目標 | ブロッカー | 対応状況 |
|-------------|----------|------------|--------------|------------|----------|
| 1           | 大       | 中         | フェーズ 2   | なし       | 完了 |
| 2           | 中       | 低         | フェーズ 2   | なし       | 完了 |
| 3           | 中       | 低         | フェーズ 2   | なし       | 完了 |
| 4           | 大       | 中         | フェーズ 2   | スイート別移行計画の確定 | 進行中（15 テスト / 26 callsite のフィクスチャ化を計画中） |
| 5           | 中       | 中         | フェーズ 3   | テンポラリ注入インターフェース設計 | 未着手（src 4 ファイル / scripts 2 本の `tempfile.mkdtemp` 廃止がタスク化されていない） |

- `_route_tempfile_mkdtemp` は `tmp_path_factory.getbasetemp()` 直下に `tempfile_mkdtemp/` を確保し、`dir` 引数を透過的に標準 API へ渡すことで `prefix` / `suffix` / `..` を含む呼び出しも従来どおり動かしつつ pytest 管理下でクリーンアップ可能な構成に更新済み（暫定策）。フィクスチャ移行完了後に段階的撤去を検討する。

## モニタリングとフォローアップ
- フェーズごとに `make test`（または `/test`）を実行し、`reports/llm_summary.*` にエラーがないことを確認する。
- 残骸検知に関する新たなメトリクス／ダッシュボードが必要な場合は、SRE と連携して計測を追加する。
- 回収した知見は `docs/guides/pytest_test_data_policy.md` に反映し、テンポラリ運用ルールの整合性を維持する。
- フェーズ完了後も半年ごとに棚卸しレビューを実施し、新たな手動テンポラリが増殖していないか確認する。
