# 開発進捗ログ

<!--
本ファイルは追記型のフル進捗ログ．

- 最新エントリは下に追記する（時系列順．古いものが上，新しいものが下）
- CLAUDE.md の「開発進捗」セクションは最新 1 行のみ（上書き運用）
- 詳細・失敗パターン・設計判断はすべて本ファイルに残す
- 書式・運用ルールは docs/01_GUIDE/GUIDE_05_エージェント運用ルール.md
  「進捗記録の運用ルール（CLAUDE.md / PROGRESS.md）」を参照
-->

- [x] **環境整備（テンプレート同期・docs 番号修正）** (2026-06-06): プログラミングテンプレートを初回同期（エージェント/コマンド/GUIDE_05 等を取り込み）し、docs カテゴリ番号を命名規則（GUIDE_03）に整合（PLAN→03 / SPEC→04 / TECH→05）。リモートをセルフホスト Git から GitHub（rintoHasegawa/TIASshot, Private）へ移行。

- [x] **CameraBase のリファクタリング（責務分離 Phase 1〜4）** (2026-06-06): 肥大化していた `CameraBase` の責務を分離。`Cameras/`・`UI/`（Phase1）、色補正→`ColorCorrection/ColorCorrector`（Phase2）、チャート検出→`ChartDetection/ChartDetector`（Phase3）、ファイル I/O・サウンド→`Utils/IoUtil`（Phase4）。
  - 動機: `CameraBase` にカメラ制御・チャート検出・色補正・ファイル I/O・サウンドが集中していた。
  - 方針: **挙動は一切変えない**（PLAN_01）。各フェーズで計算/検出/I-O ロジックが元コードと文字単位で一致することを確認し、ビルドは全フェーズ 0 エラー 0 警告。
  - 設計判断（PLAN_01 当初案からの変更）: 派生クラス（IScam/Lucam）と共有する状態に結合するメンバーは分離先に移さず `CameraBase` に残した。具体的には `UpdateRate`/`GetRatio`（ゲイン補正）、`SetSaveFolder`/`WriteInfo`/`SetInfo`（`_saveFolder`/`_ShotInfo` 経由）。後者 2 つは純粋ロジックのみ `IoUtil` へ移し、`CameraBase` 側は薄いラッパーとした。
  - 回帰検証: リファクタ前に実機で基準データ（`_基準データ_refactor前/`、特に `TCC_RGB.csv`）を取得して保管。実機の再校正は物理入力が変わり数値が一致しないため、回帰は「同一入力での計算一致」＋「コードの文字単位一致」で担保した。

- [x] **CameraBase リファクタリング Phase 5（IScam/Lucam の重複処理を集約）** (2026-06-07): Phase 1〜4 後も派生クラスに残っていたプレビュー/校正フローと撮影ループの重複を、`CameraBase` のテンプレートメソッドに集約。カメラ固有のゲイン反映・フレーム取得・撮影前後処理のみ抽象メソッドで派生クラスに残した。
  - 方針: **挙動は一切変えない**。自動テスト不可（ハードウェア/ネイティブ/WinForms 密結合）のため、ビルド 0/0 ＋ diff の処理順序目視一致 ＋ 実機撮影確認で担保。
  - 設計判断: `IScam` の撮影前後処理（Sink 切替・最初のフレーム捨て）は `Lucam` と実行順序が異なるため共通骨格に取り込まず派生側に残した（順序維持を優先）。
  - 失敗パターン: 校正収束時のデバッグログを撮影情報記録とまとめて `CalcTcc` の後に移したことで元の「ログ→CalcTcc→記録」順がずれた → テストで検出し、`CalcTcc` 前に呼ぶ専用フックへ分離して厳密な順序一致を回復。

- [x] **PLAN_02 優先度1: `_shots` のスレッドセーフ化（連続撮影クラッシュ修正）** (2026-06-07): 連続撮影で4枚以上取得するとたまにクラッシュする不具合を修正。根本原因は `_shots`（`List<Mat>`）を撮影スレッドと保存スレッドで無保護に共有していたこと（容量拡張時のリサイズ競合・TOCTOU）。
  - 設計判断: `ConcurrentQueue` 単体ではなく `BlockingCollection<Mat>` を採用し生産者-消費者パイプライン化。`GetConsumingEnumerable`/`CompleteAdding` で `Thread.Sleep` ポーリング待機を排除。保存連番は独立カウンタで従来順序を維持。
  - 堅牢化: 撮影ループを `try/finally` で包み、例外時も `CompleteAdding()` を必ず呼んで消費者（保存スレッド）の永久ブロックを防止（例外はそのまま伝播。ユーザー向けエラー表示・撮影中断は優先度3 で別途）。
  - 回帰検証: 自動テスト不可（ハードウェア依存）のため、ビルド 0/0 ＋ 実機（校正・連続撮影・複数回・連番一致）確認 ＋ 設計レビューで担保。

- [x] **テスト方針（GUIDE_08）整備** (2026-06-07): 立ち上げフローの規約整備フェーズが未着手だったため、品質管理の土台としてテスト方針を策定。ハードウェア結合層（カメラ/UI/スレッド）と純粋ロジック層を分け、後者を NUnit で自動テスト、前者をビルド＋手動＋実機回帰で担保する方針。
  - 動機: `/implement` のテストフェーズが毎回「テスト不可」で終わっていたが、実態は純粋ロジック層（`ColorCorrector` 等）にテストプロジェクトを立てていなかっただけ、という認識のズレを是正。
  - 後段: テストプロジェクト（`TIASshot.Tests`, NUnit / x64 / .NET Framework 4.8）の立ち上げと `ColorCorrector`・`Config`・`IoUtil` 等の初期テスト作成（次ステップ）。

- [x] **エラーハンドリング方針（GUIDE_09）整備** (2026-06-07): 既存の実装パターン（`ErrorMsg`＋`bool` 返却・`MessageBox`・`Debug.WriteLine`・`ShowMessage`）を土台に，エラーの分類（起動時致命／処理中の回復可能／プログラミングエラー）・処理方法・ログ方針を軽量に標準化。
  - 動機: PLAN_02 優先度3（撮影中の例外をクラッシュさせずエラー表示・中断する修正）の前に方針を確定し，場当たり実装を避けるため。
  - 設計判断: ログは `Debug.WriteLine` のみとし永続ログファイルは作らない（撮影現場での解析が必要になったら別途見直す）。空 `catch` 禁止・例外時のスレッド同期資源の `finally` 終端を明文化。
  - 残: GUIDE_06 コーディング規約・GUIDE_07 ディレクトリ構造規則は未整備のまま（既存の de-facto 確立により優先度低）。

- [x] **テストプロジェクト立ち上げ（TIASshot.Tests, NUnit）** (2026-06-07): GUIDE_08 に従い，ピュアロジック層を自動テストする基盤を構築。`ColorCorrector`（次元拡張・変換行列・色変換）・`Config`（パース）・`IoUtil`（CSV 往復）に初期テストを追加。
  - 設計判断: 本体が packages.config 方式のレガシー形式のため，テストも同形式 x64 で統一（`OpenCvSharp4.runtime.win` のネイティブコピー規則をそのまま機能させ，`dotnet test` ではなく `vstest.console.exe /Platform:x64` で実行）。NUnit 3.14 を採用。
  - テスト容易化のシーム（挙動不変）: 本体に `[InternalsVisibleTo("TIASshot.Tests")]` 追加，`ColorCorrector` の純粋メソッドを private→internal・チャネル配列を受け取る internal コンストラクタ追加，`Config.Load(string path)` オーバーロード追加。
  - ハマり所: テストでも OpenCvSharp ネイティブ DLL の **x64 ロード**が必須（`IoUtil` の CSV テストが通る＝ネイティブ動作の試金石）。`.gitignore` を汎用 `bin/`・`obj/` に変更し，テストプロジェクトの成果物も除外。
  - 後段: `GetRatio`（ゲイン補正式）は `CameraBase`（ハードウェア結合層）にインラインのため未テスト。抽出すればテスト候補。ENV_02 のメインソース一覧がリファクタ前構成のままドリフトしており，別途修正が必要。

- [x] **docs ドリフト修正（ENV_02・TECH_01）** (2026-06-07): リファクタリング（Phase 1〜5）後も旧構成のまま残っていたドキュメントを実構成に整合。ENV_02 のソース一覧をサブフォルダ構成に、TECH_01 のファイルパス・クラス一覧（`ChartDetector`/`ColorCorrector`/`IoUtil` 追加）・`CameraBase` メンバ（移動した `ConvertImage`/`_convRGB2SRGB` 削除）を修正。

- [x] **ゲイン補正式（GetRatio）の純粋メソッド抽出＋テスト** (2026-06-07): `CameraBase` にインラインだったゲイン更新比率の計算式を，ハードウェア非依存の純粋クラス `GainCalc.CalcRatio` に抽出し，`CameraBase.GetRatio` は委譲に変更。`TIASshot.Tests` でテスト対象化（GUIDE_08 の「ピュアロジック層を分離して自動テスト」方針の実践）。
  - 方針: **挙動不変**。式・演算順序・`float` 比較・ゼロ除算挙動・`UpdateRate` の流れをすべて保持し，派生クラスの呼び出し箇所は無変更。実機で校正（ホワイトバランス自動調整）の収束を確認。
  - テスト観点: 通常比率・`updateRate` 減衰・下降補正（`target<value`）・`value==target`→1.0・`value==255` の係数 1.0 特別扱い・`updateRate=0` の更新停止・ゼロ除算（`Infinity`/`NaN`）の現状固定。

- [x] **PLAN_02 優先度2: `ConvertImage` の中間 Mat 未 Dispose（OOM クラッシュ）修正** (2026-06-07): 連続撮影で `ColorCorrector.ConvertImage` 内の中間 Mat（`flatten`/`extended`/`converted`/`convertedImage`）が解放されず数十 GB 規模で蓄積し OOM クラッシュする不具合を，入れ子 `using` で確実に Dispose して修正。
  - 方針: **挙動不変**（解放タイミングのみ変更）。返り値 `convImg8` は `using` の外で `ConvertTo` のコピー後に返却し use-after-dispose を作らない。テスト容易化のため `private`→`internal`（挙動不変）。
  - テスト: テスト基盤が整ったため**自動回帰テストで担保**（恒等 conv での出力ピクセル一致＝破損なし，3 回連続呼び出しの解放健全性等）。実機でも校正・1枚・連続10枚の出力健全を確認。
  - 後段: 優先度4（`ConvertImage` の `src` in-place 書き換え）は未修正。現状挙動をテストで記録済み（修正時に検出可能）。

- [x] **白板撮影モード（照明均一性評価用・DEBUG 限定）** (2026-06-07): SmTIAS との装置間比較（照明均一性評価）用に、ImagingSource DFK 23UX249 を対象とした白板撮影機能を追加。`#if DEBUG` 限定で配布版には出さない。
  - 動機: SmTIAS-Evaluation 側と「TIAS の白板撮影が線形・無加工・固定設定で行えるか」を確認した回答（手元の参照資料 TECH_02/SPEC_03）に基づく実装。色を合わせるのが目的でないため**校正（チャート検出・WB 自動調整・TCC 色補正）を一切行わず素の RGB を保存**する独立撮影パスとした（既存の舌診撮影フローは不変）。
  - 設計判断: 撮影前に DFK23 の Color Enhancement を OFF（非線形の色強調を排除）。飽和統計（飽和率・p99・ch別 mean/max）と撮影条件を JSON サイドカーで併置。統計算出と JSON 生成はピュアロジック（`Utils/ImageStats`）に分離し自動テスト（GUIDE_08）。実機で 10 枚撮影・Color Enhancement OFF・飽和率0・p99=181（露出適正）を確認。
  - 保留・後段: LSC/ビネット補正は未実装（JSON に「未補正」と状態記録のみ）。フラットフィールド/ダークフレーム撮影・Lucam 対応は未対応。白板撮影後に Color Enhancement が OFF のまま戻らない（同一セッションで通常撮影に戻る場合は要再起動。`finally` での状態復元は今後の検討事項）。JSON の固定状態文字列（gamma_setting 等）は device-state 由来の決め打ちで動的読取ではない。
