Newer
Older
TIASShot / docs / PROGRESS.md

開発進捗ログ

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

  •  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)を取得して保管。実機の再校正は物理入力が変わり数値が一致しないため、回帰は「同一入力での計算一致」+「コードの文字単位一致」で担保した。

  •  CameraBase リファクタリング Phase 5(IScam/Lucam の重複処理を集約) (2026-06-07): Phase 1〜4 後も派生クラスに残っていたプレビュー/校正フローと撮影ループの重複を、CameraBase のテンプレートメソッドに集約。カメラ固有のゲイン反映・フレーム取得・撮影前後処理のみ抽象メソッドで派生クラスに残した。

    • 方針: 挙動は一切変えない。自動テスト不可(ハードウェア/ネイティブ/WinForms 密結合)のため、ビルド 0/0 + diff の処理順序目視一致 + 実機撮影確認で担保。
    • 設計判断: IScam の撮影前後処理(Sink 切替・最初のフレーム捨て)は Lucam と実行順序が異なるため共通骨格に取り込まず派生側に残した(順序維持を優先)。
    • 失敗パターン: 校正収束時のデバッグログを撮影情報記録とまとめて CalcTcc の後に移したことで元の「ログ→CalcTcc→記録」順がずれた → テストで検出し、CalcTcc 前に呼ぶ専用フックへ分離して厳密な順序一致を回復。

  •  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 + 実機(校正・連続撮影・複数回・連番一致)確認 + 設計レビューで担保。

  •  テスト方針(GUIDE_08)整備 (2026-06-07): 立ち上げフローの規約整備フェーズが未着手だったため、品質管理の土台としてテスト方針を策定。ハードウェア結合層(カメラ/UI/スレッド)と純粋ロジック層を分け、後者を NUnit で自動テスト、前者をビルド+手動+実機回帰で担保する方針。

    • 動機: /implement のテストフェーズが毎回「テスト不可」で終わっていたが、実態は純粋ロジック層(ColorCorrector 等)にテストプロジェクトを立てていなかっただけ、という認識のズレを是正。
    • 後段: テストプロジェクト(TIASshot.Tests, NUnit / x64 / .NET Framework 4.8)の立ち上げと ColorCorrector・Config・IoUtil 等の初期テスト作成(次ステップ)。

  •  エラーハンドリング方針(GUIDE_09)整備 (2026-06-07): 既存の実装パターン(ErrorMsg+bool 返却・MessageBox・Debug.WriteLine・ShowMessage)を土台に,エラーの分類(起動時致命/処理中の回復可能/プログラミングエラー)・処理方法・ログ方針を軽量に標準化。

    • 動機: PLAN_02 優先度3(撮影中の例外をクラッシュさせずエラー表示・中断する修正)の前に方針を確定し,場当たり実装を避けるため。
    • 設計判断: ログは Debug.WriteLine のみとし永続ログファイルは作らない(撮影現場での解析が必要になったら別途見直す)。空 catch 禁止・例外時のスレッド同期資源の finally 終端を明文化。
    • 残: GUIDE_06 コーディング規約・GUIDE_07 ディレクトリ構造規則は未整備のまま(既存の de-facto 確立により優先度低)。

  •  テストプロジェクト立ち上げ(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 のメインソース一覧がリファクタ前構成のままドリフトしており,別途修正が必要。

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

  •  ゲイン補正式(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)の現状固定。

  •  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 書き換え)は未修正。現状挙動をテストで記録済み(修正時に検出可能)。

  •  白板撮影モード(照明均一性評価用・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(露出適正)を確認。
    • 追加(フルフレーム保存): ビネット(周辺減光)は ROI で切り出すと四隅が消えて見えないため、フレームごとに ROI 画像(WhiteBoard_*)に加えクロップなしのフルフレーム(WhiteBoard_full_*)も保存。飽和統計は ROI のみ(白板領域の露出チェックが目的)。実機で full=1200×1920・ROI=1136×1528 が設定どおりと確認。
    • LSC 調査結果: DFK 23UX249 は産業用カメラで在カメラのレンズシェーディング補正を持たない(device-state の全プロパティに項目なし+公式仕様にも記載なし)。補正データも付加されない。→ ビネット除去は SmTIAS 推奨の「独立な一様光源でのフラットフィールド」一択(在カメラ補正は不可と確定)。
    • 保留・後段: LSC/ビネット補正は未実装(JSON に「未補正」と状態記録のみ)。フラットフィールド/ダークフレーム撮影・Lucam 対応は未対応。白板撮影後に Color Enhancement が OFF のまま戻らない(同一セッションで通常撮影に戻る場合は要再起動。finally での状態復元は今後の検討事項)。JSON の固定状態文字列(gamma_setting 等)は device-state 由来の決め打ちで動的読取ではない。

  •  白板撮影の出し分けを専用ビルド記号 WHITEBOARD に変更 (2026-06-18): 白板撮影モードを #if DEBUG から独立した #if WHITEBOARD に切り替え、Form1.Designer.cs の条件コンパイルを全廃(白板ボタンを専用 partial ファイルに分離)。あわせて白板ボタンの長年のレイアウト衝突(データ保存フォルダ欄との重なり)を修正。撮影ロジックは不変。

    • 動機: 「デバッグビルドか」と「白板撮影を含めるか」は別関心事なのに DEBUG で結合していた。本番(Release)からの除外は維持しつつ独立制御できるようにする。Designer.cs に #if が入っていると WinForms デザイナで破損するリスクがあったため全廃が主目的。
    • 設計判断: 専用ビルド記号案 vs 実行時 config フラグ案。本番バイナリにコードごと残さず除外したい要件から前者を採用(Debug 構成にのみ WHITEBOARD を定義、Release は未定義)。
    • UI: 白板ボタン配置は試行の末「1 枚撮影」直下の空き帯に収めた(フォーム下端拡張案は「下すぎる」ため不採用)。WHITEBOARD ビルド時のみ実行時に動的追加するため本番レイアウトは不変。

  •  PLAN_02 メモリ修正の効果検証ツール(NUnit ベンチ+実アプリ統合のメモリ観測ウィンドウ) (2026-06-23): 優先度2(ConvertImage 中間 Mat 解放)の効果を定量・デモ両面で検証できるようにした。定量は NUnit [Explicit] ベンチ(修正前リーク再現 vs 修正後を同条件反復し PrivateMemory/WS の peak・増分を比較)。デモは TIASshot 本体に統合したメモリ観測ウィンドウ(MEMMONITOR 記号・起動時自動オープン・Timer サンプリングのライブ折れ線+CSV)で実使用時のメモリをライブ可視化。

    • 動機: 研究室への成果共有のため、実アプリを普通に使った(撮影した)ときのメモリ挙動を録画して「修正前→修正後」を対比で見せたい、という要件。当初は独立実験アプリ(合成ベンチ GUI)を作ったが、用途に合わず本体統合へ転換。
    • 設計判断(失敗パターン圧縮): ① 独立実験アプリ案 → 「普通にアプリを使ったときの挙動」が見せられず破棄 ② 本体統合のライブ観測ウィンドウへ。出し分けは白板と同じビルド記号方式(MEMMONITOR、Release 除外)。さらに対比録画用に LEAKY_REPRO 記号で ConvertImage を修正前(中間 Mat 未解放)に戻せるようにした(既定未定義=修正後)。
    • 計測の要点: Mat はネイティブメモリで GC.GetTotalMemory では捕捉不可 → Process.PrivateMemorySize64/WorkingSet64 を使用。OpenCvSharp が GC にメモリ圧を通知するためリーク版でも GC+ファイナライザで周期回収が起き、グラフはのこぎり波になる(見るべきは振れ幅でなくピーク包絡線のトレンド:修正後=天井一定、リーク=上昇)。
    • 後段: 優先度5(_shots/_chartMasks の Clear 時未解放)は未修正のため LEAKY_REPRO の対象外(対比は優先度2のみ)。グラフのトレンド可視化(包絡線・移動平均等)は要望次第で追加余地。

  •  連続撮影フロー再現のメモリ計測ベンチ+計測結果レポート (2026-06-23): 既存の単体ループベンチ(ConvertImage 隔離)では本番の連続撮影フローを再現できていなかったため、カメラ取得部だけを合成フレームに差し替えて本番フローを構造再現するベンチ(ContinuousShootMemoryBenchmark)を追加。生産者-消費者スレッディング・1 フレーム複数チャンネル変換・フレームバッファを含む。修正前/後の計測結果を docs/06_TEST/TEST_03_メモリ修正効果計測.md にまとめた(カメラ実機不要・ヘッドレスで Claude 側が実行可能)。

    • 設計判断: 本番 CameraBase.RunShotLoop/SaveThread/SaveImages を直接ヘッドレス実行するには Form1・Config・TCC・校正で埋まる _convRGB2SRGB 依存が重すぎる → 本番コード無改造のまま「フローの構造再現」を選択(本番メソッドそのものの呼び出しではない旨を明記)。リーク再現と計測ユーティリティは MemBenchSupport に共有化し既存ベンチと統一。
    • 結果の要点: フロー再現フルスケールで修正後増分は修正前の約 34%(per-frame 112 vs 326 MB)。単体隔離(約 17〜20%)と数値が違うのは、フロー版がフレーム保持+多チャンネル+並行処理の一時メモリを含むため。
    • 役割分担の整理: メモリの「数値」はベンチ(Claude 側・再現性高)で、実使用の「動画デモ」は MEMMONITOR +実機録画(人間)で、と用途を分けた。

  •  PLAN_03 プレビューメモリリーク修正+派生クラッシュ・副モニタ描画飢餓の解決 (2026-07-11): PLAN_03(撮影経路とは別系統の「プレビュー表示中の長時間クラッシュ」)の原因1〜3(ShowImage のフルコピー Bitmap リーク・表示バッファの取りこぼし未 Dispose・PreviewMonitor.UpdateImage の上書き前未 Dispose)を修正。実機検証の過程でさらに 2 件(Lucam のクロススレッド GDI クラッシュ・副モニタの描画飢餓)が発覚し、あわせて解決した。実機のメモリ観測(MEMMONITOR)で反復検証。

    • 動機: ver1.6 から続く「プレビュー表示のまま放置で落ちる」不具合。GDI ハンドル/ネイティブ画素バッファの蓄積が疑われた。
    • 設計判断(表示バッファの所有権統一): 表示用 Bitmap は必ず「カメラがコールバックスレッドで Dispose するバッファ」とは別の UI 側所有コピーにする。Lucam は二重バッファ _bmps[] をコールバックスレッドで Dispose するため、それを直接 picDisplay.Image に載せると UI の OnPaint と衝突し「オブジェクトは現在他の場所で使用されています」で落ちる(v1.6 からの潜在バグ)。→ 入力 bmp は「読むだけ」に統一し、表示は UI 所有コピー、入力の Dispose 責任は呼び出し側(IScam は自分の ToBitmap を破棄)に置く。BeginInvoke 案は Lucam の「ShowImage 直後に _bmps を Dispose」する同期前提を壊すため不採用。
    • 失敗パターンの圧縮(副モニタ描画飢餓): ① 描画コスト増/GDI ハンドル枯渇/画像サイズ肥大を疑う → MEMMONITOR にプレビュー計測(各段 FPS・コピー時間・実描画時間・GDI/USER/handle 数・画像サイズ・校正/撮影/F9 イベントを CSV 化)を追加して全て計測で否定 → ② 真因は「セカンダリ(非アクティブ)ウィンドウの WM_PAINT 飢餓」。校正完了で DetectChart が止まりコールバックが高速化 → コールバックスレッドからの毎フレーム Invalidate() 洪水で Form1 が常時 WM_PAINT 保留になり、同一 UI スレッドを共有する副モニタが飢餓(sub_paint_fps≈2)。
    • 失敗パターンの圧縮(対策): ① 副モニタのみタイマー駆動化 → WM_TIMER < WM_PAINT の優先度により Form1 の Invalidate 洪水が副モニタのタイマーを飢餓させ、ほぼ無効 → ② 本モニタ含めコールバックスレッドからの毎フレーム Invalidate を全廃し、両プレビューを自ペースの UI タイマー(≒30fps)駆動に統一。洪水源が消え副モニタが steady ~10fps に回復(本モニタと公平に共有)。
    • 検証の要点: sub_paint_ms(実描画時間)が崩壊中も低いまま=描画は軽い、img_w/h 一定=画像肥大でない、gdi_objects が上限(1万)に対し桁違いに小さい=ハンドル枯渇でない、という三点の否定でスケジューリング(メッセージ枯渇)に原因を絞り込めた。
    • 計測スカフォールドは MEMMONITOR 限定(Release 未含有)でそのまま残置(今後の検証・GDI 観測用。PLAN_03 も GDI 数観測を推奨)。
    • 後段: 両プレビューの上限 ~10fps は毎フレームのフルフレーム Bitmap コピー(各 ~25ms)が律速だったため、別コミットで高速化(下記)。Phase 2/3(自動テスト・リファクタ)は本変更が WinForms UI スレッド・GDI ライフサイクル・カメラコールバック並行性主体で既存ユニットテスト基盤の対象外のため、実機メモリ計測での検証に代替(ユーザー指示によりこの検証済み状態でコミット)。

  •  3 バージョン(v1.6/v1.7/現行)の性能評価計測 (2026-07-14): 上流 v1.6/v1.7 と現行フォークを実機 MEMMONITOR で同一プロトコル計測し、メモリリーク・フレームコピー時間・プレビュー FPS を横並び比較。改善が「保存経路 v1.6→v1.7」「プレビュー経路 v1.7→現行」の 2 段階で起きたことを定量化(計画 PLAN_04・結果 TEST_02、PR #18 で main へ)。

    • 動機: 研究室共有用に、素の上流版と現行の性能差を録画+スライドで示したい。数値ベンチ(TEST_03)ではなく「普通にアプリを使ったときの実挙動」を対象にした。
    • 計測基盤: 観測ウィンドウのグラフを左軸メモリ+右軸 FPS(本/副モニタ)の 2 軸化し、起動時に本体+観測窓を録画向けに自動配置。基準記録(校正→単発撮影 30 秒間隔×3→放置 180 秒)の秒数を全版で再現。
    • 旧版移植(設計判断): bench/v1.6・v1.7(throwaway・非マージ)へ観測フックのみ注入しプレビューのロジックは不変(リーク・コピー方式・Invalidate タイミングを保存)。v1.7 は v1.6 の移植を cherry-pick で流用(プレビュー経路が同一のため)。
    • 失敗パターンの圧縮: 旧版は毎フレーム Invalidate で本体 UI スレッドが飽和し、同一スレッドの観測窓がグラフ描画・サンプリングともに WM_PAINT 洪水で飢餓(更新が遅い・サンプル間隔が乱れる)→ 観測窓を専用 UI スレッドへ分離(測定中立)+WS_EX_COMPOSITED でラベルのちらつき抑制。
    • 結果: メモリ包絡線 v1.6 ~890MB → v1.7 ~700MB → 現行 ~200MB で平坦。コピー ~46ms(new Bitmap)→ ~2.6ms(FastClone)。副モニタ FPS ~3(飢餓)→ ~19。v1.6/v1.7 のプレビュー指標が数値まで一致=プレビュー経路が v1.7 まで未修正だった裏付け。

  •  完了済み計画(PLAN_01/02)の削除と LEAKY_REPRO フラグの撤去 (2026-07-14): 完了済みで本ログに要点が残る PLAN_01(リファクタリング)・PLAN_02(バグ修正)を削除し、削除ファイルへの実リンク・ファイル名参照を整理(歴史的言及は残置)。対比デモ用ビルドフラグ LEAKY_REPRO とその分岐コードを撤去。

    • 動機(LEAKY_REPRO): 3 版評価の完了で「旧版そのもの」が修正前を担うようになり、現行コード内でリークを再現する対比用フラグが不要になった。
    • 撤去内容: ColorCorrector.ConvertImage のリーク分岐を除去し修正版(入れ子 using)のみに、観測窓のモード表示(lblMode)を Designer 含め削除、ENV_06/PLAN_04 の記述も削除。標準構成では未定義のデッドコード除去のため挙動不変(ビルド成功・色補正テスト全パスで確認)。

  •  プレビューのフレームコピーを LockBits で高速化 (2026-07-11): プレビュー表示経路で毎フレーム生成する Bitmap コピー(new Bitmap(bmp))が 1 回 ~25ms かかり、コールバックスレッドの律速で実効 ~10fps に頭打ちだった問題を、生画素の直接コピーに置換して解消。実機計測で コピー 25ms→2.5ms(約10倍)、callback_fps 16→30、両プレビュー描画 10→20fps を確認。

    • 原因: new Bitmap(Image) は内部で 32bppARGB への変換を伴う GDI+ DrawImage 経路を通るため遅い。プレビューは 24bppRgb(Mat.ToBitmap() 由来)で、同一フォーマットの生画素をそのままコピーすれば足りる。
    • 方針: LockBits で src/dst の生画素ポインタを取得し RtlMoveMemory(kernel32)で行単位ネイティブコピーする FastClone(/unsafe 不要)。生成物は入力と独立した画素バッファ=所有権・スレッド安全性(Lucam クロススレッド Dispose と非衝突)は従来の new Bitmap(bmp) と同一で不変。src は ReadOnly ロックのみで非破壊。インデックスカラー(8bpp 以下・パレット保持要)は安全網として従来の GDI+ フルコピーにフォールバック(この経路は色は等価だが PixelFormat が 32bppArgb に変換される点に注意)。
    • テスト方針(本 PLAN_03 一連の実装共通): 自動 NUnit テストで担保できるのは純ロジックの FastClone のみ(独立コピー・src 非破壊・ストライドパディング・Indexed フォールバック・null)。プレビューのタイマー駆動描画・_dispBufLock を介したクロススレッド Dispose の所有権・WM_PAINT/WM_TIMER のスケジューリングは UI スレッド/GDI/実カメラ・副ディスプレイ結合層でユニットテスト不能のため、実機 MEMMONITOR 計測(コピー時間・各段 FPS・GDI/handle・描画時間の CSV)で反復検証した。

  •  自律監査ループ(/auto-audit)の実施と撮影失敗の無通知データ破損の修正 (2026-08-03〜04): コードベース全体をバグ・脆弱性観点で巡回監査し,再現テストで正しさを証明できたものだけを自動修正(保存パスの無害化,設定値パース,資源解放,ロケール依存,ゲインのクランプ等).続けて監査で重大度「高」と判定した Lucam の撮影失敗無通知を /implement で修正した.

    • 動機(監査): 修正の正しさを人間確認なしで担保するため,「独立した反証で誤検知を殺す → 再現テストで赤を作る → 影響範囲を特性化テストで保護する → 検証スイート全緑で初めてコミット」の 4 ゲートを課した.証明できないもの(UI・カメラ結合層,仕様判断が要るもの)は直さず報告に落とす方針.
    • 設計判断(撮影失敗時): 「即中止+ダイアログ通知」をユーザーが選択.取得済み画像は破棄せず残し,Info.csv に中止理由を記録する(データを消すより残す方が非可逆な損失を避けられるため).
    • 失敗パターンの圧縮: ① 中止通知を撮影ループ内で出す → MessageBox のモーダルループがメッセージをポンプするため,保存スレッドの EnableShots(true) がダイアログ表示中に届き,撮影終了処理(LucamDisableFastFrames / Sink 復帰)未完了のまま再入し得る → ② 通知を Shot() の戻り直後へ移動.EndShot() 直後ではなく Shot() 戻り後にしたのは,IScam が EndShot() 空実装で実処理を Shot にインライン展開しているため.
    • 中止状態は _shotAborted(保存スレッドが読むため volatile)と中止理由(UI スレッド内で完結)に分離した.統合すると「想定外例外による中止(理由なし・通知しない)」が表現できなくなるか可視性の前提が崩れるため,統合せずコメントで意図を明示.
    • 後段: 監査で自動修正しなかった指摘は .claude/auto-audit-report.md に集約(要人間対応).とくに撮影経路の例外境界(btnShot*_Click の try-catch 欠如,BeginShot 例外時に CompleteAdding() へ到達せず UI が固着する穴,想定外例外時に EndShot() がスキップされる件)は同根で,まとめて設計で潰すのが望ましい.

  •  撮影経路の例外境界を整備し例外時の UI 固着とスレッドリークを解消 (2026-08-10): 監査で報告に落としていた同根 3 件(撮影ボタンハンドラに例外境界が無い/CompleteAdding() 未到達で保存スレッドが永久ブロックする/想定外例外で撮影終了処理がスキップされる)をまとめて修正し,あわせて保存スレッド自身の例外境界も追加した.

    • 動機: いずれも「例外が出た瞬間に撮影ボタンが二度と有効化されず,アプリ再起動が必要になる」「バックグラウンドスレッドの未処理例外でプロセスが即終了する」という,現場では原因の分からない障害として現れる.同根なので個別に塞ぐと穴が残ると判断した.
    • 設計判断: 撮影ボタンの再有効化は保存スレッドの最終行が唯一の実行者とし(保存中の再入を封じる従来の不変条件),保存スレッド未起動の経路だけ UI 層が復帰させる.UI 層は下位層の状態を読み取り専用プロパティで問い合わせる形にし,下位層から UI を呼ばない原則を維持した.
    • 失敗パターンの圧縮: ① 例外を捕まえた UI 層で即座に再有効化 → モーダル表示中もメッセージがポンプされるため保存中にボタンが押せ,次の撮影の Join と保存スレッドの Invoke が相互待機してアプリが完全ハング → ② 保存スレッド起動後は UI 層が有効化しない方式へ.③ さらに「起動済みフラグ」のリセットが Shot 内だったため,保存フォルダ作成失敗など Shot 到達前の例外では前回の値が居座り 2 回目以降が固着 → ④ スレッド生存判定との併用+撮影要求の先頭でのリセットで解消.
    • 保存スレッドの中断時は未消費の Mat を必ず解放する.打ち切り上限は総経過時間ではなく無通信時間にした(総経過だと長時間の連続撮影で正常時に誤爆し,逆にリークと撮影中のボタン有効化を招くため).
    • 後段: 白板撮影(WHITEBOARD 限定)が通常の撮影ボタンと排他になっていない点は未対応.再校正機能を追加する場合は「撮影ボタンは保存完了まで有効化されない」前提が崩れ,上記①のハングが復活し得るため再入制御の設計から見直すこと(コードのコメントにも明記済み).

  •  テンプレートを最新版に同期(補助エージェント・依存更新・テンプレート改変台帳の導入) (2026-08-28): /sync-template で programming-template を 061d1c4 → 0ac68c7 に追従.補助エージェント(advisor/deps-analyst/ops-runner)と skill(/consult・/deps-update・/commit merge),テンプレート改変台帳(.claude/template-overrides.md+template-customization rule)が入った.

    • 設計判断: テンプレート側で task-* skill が team 層から共通層に移り,solo でも Issue ベースのタスク管理を併用できるようになったため配置した.進捗記録(本ファイル+CLAUDE.md 進捗欄)は従来どおり運用し,Issue は補助として扱う.
    • マージ必須ファイルは上書きせず差分統合した(.gitignore は VS/NuGet 等の固有ルールを保持,CLAUDE.md は共通セクションのみ更新,settings.json は既存の PreToolUse フック配線を保持して permissions.allow を追加).テンプレート由来ファイルのローカル改変は 0 件だったため台帳は空で開始.
    • 続けて,新しい GUIDE_01 が前提にする Dependabot をセットアップした.リポジトリ設定(alerts / security updates)を gh api で有効化し,.github/dependabot.yml(NuGet: TIASshot/TIASshot.Tests の packages.config,週 1 回,マイナー/パッチをまとめる.メジャー更新も個別 PR で作らせる.GitHub Actions も対象)を追加した.手順は ENV_03 に転記.
    • 後段: CI(GitHub Actions)が無いため,/deps-update のマージゲートはローカル検証(x64 ビルド+テスト)で判定することになる.OpenCvSharp や実機カメラ SDK に関わる更新は実機確認が要る点は変わらない.

  •  初回の /deps-update 実行:Dependabot PR 5 件が全てビルド不能と判明し,追従を Issue 化 (2026-08-28): 初回の依存更新巡回で open な Dependabot PR 5 件(メジャー 4・マイナーグループ 1)を検証した結果,マージ可能なものは 1 件も無かった.前エントリの後段で予告したとおりローカル検証(x64 ビルド+テスト)がゲートとして機能し,GitHub 上は全件 MERGEABLE / CLEAN だった破壊的変更を水際で止めた.追従作業は #29〜#32 として起票し,本コミットはうち #32 を実施.

    • 原因①(グループ PR #24): minor-and-patch グループに入っていた OpenCvSharp4 の bump が,semver 上は minor ながら ArUco API を破壊していた(PredefinedDictionaryName の廃止・改名,CvAruco.DetectMarkers の削除).OpenCvSharp のバージョンは OpenCV 本体に追随しており semver 契約を持たないため,第 2 セグメントの bump は常にメジャー相当として扱う必要がある.グループ PR は部分マージできないので,専用グループに分離しない限り残り 12 パッケージも道連れで止まる(#29).
    • 原因②(メジャー 4 件): Dependabot の packages.config アップデータが,同時 open の他 PR の解決結果を csproj に混入させ,どの PR も「csproj が自分の packages.config に無いパッケージのパスを参照する」状態になっていた.csproj はパスにバージョンがハードコードされる形式のため,EnsureNuGetPackageBuildImports の <Error> が発火して確実にビルドが落ちる.根本原因は packages.config 形式そのもので,テストプロジェクトの PackageReference 移行が構造的対策になる(未着手).
    • 設計判断(NUnit 4 追従の順序): ClassicAssert への置換は NUnit 3.14 でコンパイルできず「上げてから直す」と main が壊れる期間ができる.一方,制約モデル(Assert.That + Is.* / Does.*)は両バージョンで動くため,先に移行しておけば破壊期間ゼロで追従できる(#30).ArUco は逆に新旧両対応の中間形が作れず,パッケージ更新とコード移行を同一 PR で原子的に入れるしかない(#31).
    • 判断待ちとして残したもの: #25・#26・#28 は net48 では更新の利得が無い(それぞれ型フォワード facade で中身同一/死んだ参照/依存 0 件→約 50 パッケージの死荷重)ため見送りが妥当だが,@dependabot ignore の投稿は人間の決定なので保留.分析結果は各 PR のコメントと .claude/deps-update-report.md に残した.
    • 付随して判明: ENV_04 の vswhere は -products * が無く,VS Build Tools のみの環境(IDE 未導入)では何も返さないため $msbuild / $vstest が解決できなかった.検証を委譲したエージェントが実際にこれで検証不能に陥ったので修正した(#32).

  •  Dependabot 追従作業の実施と,クリーンビルドでのみ顕在化する依存欠落の発見 (2026-08-29): 前エントリで起票した #29・#30・#32 を実装してマージし,#31(ArUco 移行)は実機確認待ちの PR として残した.その検証過程で,main に元から存在した「クリーンビルドするとテスト 41 件が落ちる」不具合を発見して修正した(#39).

    • 失敗パターン(最重要): bin に前回のビルド成果物が残っていると,過去にコピーされた DLL でアセンブリ解決が偶然成立し,依存の記述漏れを隠してしまう.テストプロジェクトは OpenCvSharp が要求する System.Memory / System.Runtime.CompilerServices.Unsafe を packages.config にも csproj にも持っていなかったが,同じマシンで作業し続ける限り誰も気づけなかった.この作業中に「main のベースラインは全緑」と誤った計測結果を一度報告している.対策として ENV_04 に「計測・マージ前検証は bin/obj を消してから,依存を変えた PR では packages も退避して nuget restore からやり直す」手順を明記した.ただし運用頼みの弱い防御なので,構造的な解は CI(#40 で起票).
    • 設計判断(推移的依存をどのバージョンで足すか): 同じ「不足している推移的依存を追加する」対処でも,要求元のバージョンによって正解が変わる.#39(OpenCvSharp 4.10 のまま)は本体と同一の現行版を足すのが正しい.4.10 が要求するアセンブリバージョンと NuGet パッケージが供給する版が厳密一致し,バインディングリダイレクトが不要になるため.一方 #31(4.13 へ更新)は依存を 4.6.x 系に上げる必要がある.4.13 の要求版はどの lib にも存在せずリダイレクトを自動生成できないので,手書きのダウングレードリダイレクトを保守し続けることになるため.「競合を避けたいから新版に先合わせする」は後者の罠を前者に持ち込むので採らない.
    • 原因(#31 側): OpenCvSharp は 4.13 で lib/net48 を廃止し lib/netstandard2.0 のみになった.net48 プロジェクトが netstandard2.0 アセンブリを消費する形になり,System.Memory 等への推移的依存が新たに発生する.packages.config は推移的依存を自動解決しないため,本体・テストの両方に明示的な参照追加が要る.
    • 後段: #31 は実機・実チャートでの確認待ち(PR #36).OpenCvSharp のネイティブ側が変わるため,合成 fixture の自動テストが緑でも検出性能・色変換の数値差は実機でしか担保できない.CI 導入(#40)が入れば /deps-update のマージゲートがローカル検証から CI 緑に変わり,判断待ちで残っている #25・#26・#28 の処理も進めやすくなる.テストプロジェクトの PackageReference 移行(推移的依存が自動解決される根本対策)は #31 マージ後・CI 導入後に検討する.

  •  テンプレートを最新版に同期(検証エージェント・フック起動ラッパー・通知フックの導入) (2026-09-18): /sync-template で programming-template を 0ac68c7 → 60ab68c に追従.検証エージェント verifier(/verify・/implement Phase 1b),Python フックの起動ラッパー run_python.sh,ntfy 通知フック notify.py とそのテストが入った.テンプレート由来ファイルのローカル改変は今回も 0 件で,台帳は空のまま.

    • 設計判断(検証プロファイルを作らない): Phase 1b は .claude/verify-profile.md がある時だけ動く任意フェーズだが,本プロジェクトでは作らない.verifier が操作するのは WinForms UI と実機カメラであり,これは .claude/rules/testing.md が「自動テスト対象外=ハードウェア結合層」と定義した領域そのもので,プロファイルを書いても担保できる範囲が増えないため.動作確認は従来どおり実機で人間が行う(Phase 1b は理由付きでスキップされる).
    • 失敗パターン: /sync-template は自分自身の定義も同期対象のため,旧ルールで走らせた処理を新ルールで見直す必要がある.今回は同期後の skill で .claude/tests/(テンプレート自身のメタテスト.派生プロジェクトでは必ず失敗する)が同期対象外に追加されており,旧ルールで一度コピーしてから取り消した.skill 自体に差分がある回は,コピー後に新しい除外規則を読み直すこと.
    • 上流に差し戻した不具合: 同期で入った test_hooks.py は 52 件中 3 件が必ず落ちる.TestCheckSync が team 層の check_sync.sh の存在をガードしておらず,solo プロジェクト全てで失敗する(programming-template#43 として起票).プロジェクト固有の都合ではなくテンプレート側の欠陥なので,ローカル改変(台帳登録)ではなく上流修正に倒した.
    • フックの前提ツール(Python 3.7 以上と bash)を ENV_02 に追記した.Python が見つからないとアクセス制限フックが Read・Write・Edit・Glob・Grep・Bash を全てブロックするため,環境再構築時に踏むと原因が分かりにくい.
    • 後段: #31(ArUco API 移行.PR #36)の実機確認待ちは変わらず継続.

  •  上流の修正を取り込み,共通層テストのチーム層依存を解消 (2026-09-18): 前エントリで programming-template#43 として差し戻した不具合が上流で修正されたため,テンプレートを 60ab68c → 3db9db5 に同期した.TestCheckSync に存在ガードが入り,solo でも失敗せず skip される(52 件中 3 件 skip で全緑).

    • 上流は個別のガード追加に留めず,「共通層のファイルはチーム層ファイルの存在を前提にしてはならない」を /sync-template の不変条件として明文化し,AST で共通層テストを検査するメタテストを追加した(メタテストは .claude/tests/ 配下のため本プロジェクトには配布されない).同種の退行は今後テンプレート側で止まる.

  •  テンプレートを最新版に同期(/setup のフェーズごとコミットと環境構築の実行) (2026-09-29): /sync-template で programming-template を 3db9db5 → 00dd94e に追従.変更は /setup 系(skill・GUIDE_01/02)と CLAUDE.md「Git 運用」の自律コミット例外への /setup 追加のみで,立ち上げ済みの本プロジェクトのコードへの影響は無い.台帳登録・未登録改変ともに 0 件.

  •  2 回目の /deps-update と NUnit 4.6.1 への移行(#27 の追従) (2026-09-29): 依存更新の巡回で,マイナー/パッチのグループ PR #44(Test.Sdk 17.14.1・NUnit3TestAdapter 4.6.0・System.* 4.6 系・System.Drawing.Common 8.0.31)をローカル検証(x64 クリーンビルド+テスト全緑)でマージした.メジャーの #45(System.Drawing.Common 10)・#46(Test.Sdk 18)は前回と同じく,他 PR の解決結果が csproj に混入してビルド不能だったため見送り(#46 は ignore を投稿,#45 は OpenCvSharp 4.13 が 10 系を要求するため #36 の後に一括追従).続けて #27 を /implement で追従し,テストプロジェクトを NUnit 4.6.1 に上げた.

    • 前回(2026-08-28)の判断どおり,制約モデルへの先行移行が効いてクラシック Assert の書き換えは 0 件で済んだ.
    • 失敗パターン: 代わりに NUnit 4.6 固有の CS0121 が出た.Assert.Throws/DoesNotThrow が TestDelegate 版(Obsolete)と Action 版([OverloadResolutionPriority])を併せ持ち,LangVersion 7.3 では優先度属性が効かずラムダの解決が曖昧になる.LangVersion を上げると古い VS / Build Tools でビルドできなくなるため,(Action) キャストで解消し,書き方を testing.md に明記した.
    • 移行前後で検出テスト名一覧(124 件,うち [Explicit] 2 件)が完全一致すること,キャストした 16 箇所がミューテーションで正しく失敗することを確認済み.
    • 後段: #27 はこのブランチの取り込み後にクローズしてよい.#31(PR #36)の実機確認待ちは継続.

  •  ヘッドレスのセルフテストモードと検証プロファイルの導入(/verify で依存更新後の確認を自動化) (2026-09-29): 依存更新(#44 のような System.* やバインディングリダイレクトの変更)後に,人間が実機を触る前に「起動時のアセンブリ解決エラーが無い・プレビュー経路が動く・校正〜保存が通る」を自動確認できるよう,TIASshot.exe --selftest(ビルドフラグ SELFTEST,Debug のみ)とランナー scripts/verify/run_selftest.py,.claude/verify-profile.md を追加した.

    • 設計判断(2026-09-18 の「検証プロファイルを作らない」判断の見直し): verifier は UI 操作もカメラ操作もできないため,当時はハードウェア結合層を担保できないと判断した.今回は「アプリ自身にヘッドレス検査モードを持たせ,verifier はコマンドを叩いて終了コードを読むだけ」にすることで,実機 SDK 以外の部分(依存ロード・CameraBase の校正フレーム処理・ShowImage/FastClone・PreviewMonitor・ChartDetector〜SaveImages)を実コードのまま通せるようにした.実カメラの代わりは CameraBase を継承した偽カメラ,実チャートの代わりはコード生成の合成チャート(実画像はリポジトリに入れない).
    • 失敗注入で検出力を確認済み(System.Memory.dll 除去・exe.config のリダイレクト改ざんで FAIL).カメラ SDK の欠落は WARN 扱いで判定しない.
    • Phase 1b(verifier)を本プロジェクトで初めて実行し,ランナーが人間の Release 成果物まで消す・packages 退避失敗で終了コードが 2 にならない,の 2 点を人間に回る前に捕捉して直した.
    • 後段: セルフテストが代替しない範囲(実カメラ SDK との結合・実プレビュー表示・実チャートの検出性能・画像の見た目・長時間のメモリ/GDI)は引き続き実機で人間が確認する.Form1.ShowImage 等が新しいコントロールを参照するようになった場合はヘッドレス用コンストラクタの追従が要る.

  •  OpenCvSharp 4.13 の ArUco API 移行を main に取り込み(#31・PR #36) (2026-09-29): 実機確認待ちで保留していた PR #36 に main(NUnit 4.6.1 移行・セルフテスト導入など 20 コミット)を取り込んで競合を解消し,実機確認を経てマージした.競合した依存設定は main 側を正とし,OpenCvSharp の 4.13 化(lib/netstandard2.0 参照・runtime の .targets 取り込み・OpenCvSharp のバインディングリダイレクト)だけを当て直した.

    • 失敗パターン: PR の保留中に main へ入ったセルフテスト(SelfTestChart・SelfTestRunner・SelfTestChartTests)が旧 API(PredefinedDictionaryName・CvAruco.DetectMarkers)で書かれており,競合解消だけではビルドが壊れる状態だった.4.10 と 4.13 の両方で動く書き方が無い API 移行を長く保留すると,その間に増えた旧 API の利用箇所も移行対象になる.取り込み時は grep で旧 API の残存を確認すること.
    • 後段: System.Drawing.Common 10 系への追従(#45)が可能になった.

  •  テスト方針を 4 層モデルに改訂し,移行計画(PLAN_05)を策定 (2026-10-06): 人間の実機確認を「SDK の実呼び出し」と「実画像の見た目」だけに絞るため,testing.md を「ピュアロジック/ハードウェア結合」の 2 層から,ピュアロジック・結合ロジック・SDK アダプタ・実機の 4 層に改訂した.段取りは PLAN_05(フェーズ 0〜5)にまとめた.

    • 動機: 同日の /auto-audit で報告した 26 件の多くが「CameraBase・Form1・カメラ層で再現テストを書けない」ことを理由に自動修正できなかった.保存失敗が成功扱いになる件など,データ欠損に直結するものも含まれていた.偽カメラとヘッドレス Form1 はセルフテスト用にすでにあり,自動化できない範囲は思っていたより狭かった.
    • 設計判断: テストプロジェクトへの System.Windows.Forms 参照の追加を許可した.CameraBase は偽カメラ+ヘッドレス Form1 で検証し,カメラ SDK はモックせずに判断ロジックを切り出す(Humble Object).実機録画データ(チャート・白板のみ.舌は個人情報のため除外)は Git LFS で管理する.層②は全体 30 秒・1 件 15 秒を上限とし,CI が無いため /verify に常に含める.
    • 後段: フェーズ 1(WinForms 参照の追加・STA ハーネスの作成・「保存失敗が成功扱い」の赤テストと修正)を /implement で行う.fix/auto-audit の取り込みは実機確認待ち.

  •  /auto-audit(全観点)の自動修正 7 件を取り込み (2026-10-06): バグ・脆弱性の巡回監査ループを初めて全観点で回し,再現テスト(修正前に赤)を書けた 7 件を修正した.内訳は NaN ゲインの設定防止,白板 JSON の制御文字エスケープ,ConvertImage と DetectChart の一時 Mat/MatExpr の解放,Info.csv の RFC 4180 クォート,セルフテストの不正な出力先で終了コード 2 を返すこと,FastClone の失敗時の解放.

    • 動機・結果: 検出した候補 40 件超のうち,自動修正できたのは 7 件だけだった.要対応 26 件(ローカルの報告台帳 .claude/auto-audit-report.md)の多くは「CameraBase・Form1・カメラ層で再現テストを書けない」ことが理由で,これを受けてテスト方針を 4 層モデルに改訂した(PLAN_05).
    • 注意: 追加したリーク再現テストのうち 2 件は環境に依存しうる(OpenCV 内部の参照カウントのオフセット読み取り,プライベートメモリ増分のしきい値判定).OpenCvSharp の更新時や別マシンで落ちたら見直す(PLAN_05 で [Category("Memory")] に分ける予定).
    • 後段: 要対応のうち重大度「中」(保存失敗が成功扱い・終了時のハングや画像の取りこぼし・校正例外がコールバックへ素通り・起動時の設定エラー・光源ポート使用中)は PLAN_05 のフェーズ 1〜3 で対応する.

  •  PLAN_05 フェーズ 1: 層②テストの共通ハーネスと保存失敗の修正 (2026-10-06): テストプロジェクトに WinForms 参照を足し,偽カメラ+ヘッドレス Form1 を STA スレッドで動かす共通ハーネスを作った.最初の利用例として,画像の保存に失敗しても「全ての画像保存完了」と表示されていた不具合(/auto-audit 報告)を,修正前に赤になる結合テストで確認したうえで修正した.

    • 設計判断: 一時 config の作成と DoEvents による待機はセルフテストのランナーから切り出し,ハーネスと共用した(2 か所で同じ待機処理を持たない).失敗の注入は,偽カメラの派生で保存先と同名のフォルダを作って ImWrite に false を返させる方法にした.保存フォルダ自体を消す案は Info.csv の作成も失敗させて別の経路に乗り,SaveThread との競合で結果も不安定になるため採らなかった.
    • 失敗パターン: 修正を一時的に戻して赤を確認したあと,ファイルを書き戻すときに更新日時が古いまま残り,MSBuild が再コンパイルせず全体テストが誤って赤になった.ファイルを戻したら更新日時も更新するか,クリーンビルドしてから判定する.
    • 後段: CalcTcc の校正画像の保存失敗(仕様判断待ち).tester・refactorer がビルドとテストを自分で実行できない問題は,テストランナー(run_tests.py)の追加で解消した(PR #55).

  •  PLAN_05 フェーズ 2: 層②テストの拡充と報告台帳 4 件の修正 (2026-10-06): 校正の状態遷移・撮影ループ・保存キューの後始末・切断・Form1 の UI 連携に,正常系と失敗注入の結合テストを広げた.あわせて,ハーネスで再現テストを書けるようになった報告台帳の 4 件(UI スレッド外の取得系メソッド,チャートマスクの解放漏れ,保存キューの取り残し,撮影失敗行のクォート漏れ)を,修正前に赤になることを確かめたうえで直した.

    • 設計判断: 保存中の切断は,SaveThread が完了表示を UI スレッドへ Invoke するまで終われない性質を使い,メッセージを処理する前に切断することでタイミングに依存せず再現した.撮影系は変換次元を 1 つに絞り,層②全体を 30 秒の目安に収めた(全次元だと約 28 秒).
    • 後段: 方針未決の挙動(CalcTcc の例外境界,終了処理,SaveThread の同期 Invoke,DrainShots の待ち時間)はフェーズ 3(束 B)で方針を決めてから扱う.テスト側に変換次元の取得処理など小さな重複が 3 ファイルに残っている.

  •  PLAN_05 フェーズ 3a: 撮影・保存の信頼性の修正(束 B) (2026-10-06): 校正中の例外をカメラのコールバックへ伝えずにやり直せるようにし,校正画像の保存失敗は警告にした.保存中は閉じるのを取り消し,閉じるときの後始末(カメラ・光源)の順序を決めた.保存スレッド等から UI への通知を非同期にし,撮影中でも保存が進むようにした.保存キューの待ち時間は撮影間隔に合わせた.方針は PLAN_05「束 B の方針」表.

    • 設計判断: 校正失敗の通知がチャート検出の進捗表示ですぐ上書きされる問題は,エラーダイアログ(カメラのコールバックを止めてしまう)ではなく,次に校正が完了するまで検出中の表示を失敗の表示に差し替える方式にした.上下逆の設置案内は,ユーザーが直すための指示なので差し替えない.
    • 失敗パターン: 通知を非同期にしたことで,「保存スレッドは UI を待つ間は必ず生きている」ことを前提にしていた保存中の切断テストが速度次第で落ちうる形になった.保存スレッドを意図的に止めておく形に書き直した.非同期化のような変更では,既存テストがタイミングの前提を持っていないかを確認する.
    • 後段: 3b(ROI・フレームバッファのサイズ検査・光源ポートの扱い).層②の実行時間が約 21〜26 秒になり目安の 30 秒に近づいている.

  •  実機自動テストの計画(PLAN_06)を策定 (2026-10-06): 層④(SDK の実呼び出し・実画像)に残る手動確認を減らすため,--hwtest で Claude が開発 PC につないだ実機のカメラ・光源を操作して検査する計画を立てた.実行はユーザーの合図があったときだけとし,保存先は一時フォルダ,設定ファイルは書き換えない.

    • 設計判断: ImagingSource は SDK の画面部品を使うため,ヘッドレスではなく実際の Form1 を表示して動かす.両機種を同時につないでも --camera で 1 台ずつ検査する(通常起動は Lumenera を優先するため).

  •  実機自動テスト(PLAN_06 フェーズ 1)を実装し,ImagingSource の実機で 7 項目が合格 (2026-10-08): TIASshot.exe --hwtest(HWTEST フラグ,Debug のみ)とランナー run_hwtest.py を作り,Claude が開発 PC につないだカメラと光源を操作して接続・プレビュー・露光/ゲイン・光源・閉じる処理・再接続・後始末を検査できるようにした.DFK 33UX178 の 2 個体で 7/7 合格し,しきい値を実測から決めた(PLAN_06).開発 PC に実機用のドライバ 3 種(LuCam Software・Cam33U Driver・CP210x)を入れ,ENV_02 に入手先を記録した.

    • 動機: 層④に残る手動確認のうち,数値で判定できる SDK の実呼び出しを人間の手から外すため(PLAN_05 の 4 層モデルの仕上げ).
    • 設計判断: チャート不要の検査も穴にカラーチャート(または白板)をはめて行い,その間は自動校正を止める.穴が空だと暗くて明るさの変化を評価しにくく,一方でチャートが写ると校正が走って検査中に露光・ゲイン・ホワイトバランスが変わるため.露光・ゲインは整数の段ではなく絶対値(秒・dB)で扱い,2^n 秒の段で動かして元の絶対値へ戻す.実測で露光 1 段は約 0.5 倍,ゲイン 1 dB は約 1.122 倍と理論どおりに効いた.
    • 仕様変更: アプリ終了時に光源を消灯しない(ポートを閉じるだけ.上流 v1.7 と同じ)とユーザーが確定した.
    • 失敗パターン: ① 同梱の DFK33UX178.xml は別個体のシリアルを持ち,旧 IScam.Connect がファイルのデバイスを開いていたため,手元の個体では接続できず例外が外へ漏れた.機種名でデバイスを開いてから設定だけ適用する形に直した(本番の接続にも効く修正).② 露光を整数の段(VCDRangeProperty)で扱っていたため,2^n でない元の露光(1/60 秒等)に戻せていなかった.絶対値で扱う形に改めた.③ Release の exe を作り直さずに確認し,古い動作を見て判断を誤りかけた.確認は必ずランナー(Debug をビルドし直す)経由で行う.
    • 後段: Lumenera は機材が未接続で未実施(つながり次第実行する).フェーズ 2(チャートが要る検査).本番の Info.csv の露光記録が整数の段を「1/10 して ms」として書いており誤った値になっている疑い(未確認.報告台帳に記録).