# 回帰テスト採取手順 (Regression Data Capture Procedure)

PLAN_02 ステップ 5「回帰テスト」で使う **旧実装 exe の入出力ペア** を採取する手順．
本作業は人間が行う（PLAN_02「人間が行う作業」）．採取した CSV を
`tests/fixtures/regression/` に置くと，`uv run pytest` の回帰テストが自動で有効になる．

- 採取物の CSV 形式: [tests/fixtures/regression/README.md](../../tests/fixtures/regression/README.md)
- 診断ロジックの仕様: [SPEC_02_診断ロジック仕様.md](../04_SPEC/SPEC_02_診断ロジック仕様.md)
- 旧アプリの操作: [SPEC_01_画面仕様.md](../04_SPEC/SPEC_01_画面仕様.md)

## 自動採取（推奨）(Automated Capture)

本手順の操作は `scripts/auto_capture.py` で**全自動化済み**（ステップ 5 で使用し，12 ケースの採取に成功）．
旧 exe の起動 → 変換行列・画像の読込 → クリック → 診断 → 8 値の読取 → CSV 追記を 1 枚ごとに繰り返す．

```bash
uv run python scripts/auto_capture.py --images-dir <単色PNGフォルダ> --matrix <変換行列.csv> --out <出力CSV> --verbose
```

- 実行中は PC を操作しないこと（ウィンドウメッセージ直送のためフォーカスには依存しないが安全のため）
- まず `--single <ファイル名>` で 1 枚試すことを推奨
- 補助: `scripts/read_legacy_values.py` は起動中の旧 exe から 8 値を読み取るだけの単体ツール（旧実装のバグで紫スコアが画面表示から読めないため，WM_GETTEXT で取得する）
- 以下の手動手順は，スクリプトが環境差で動かない場合のフォールバックとして残す

## 目的 (Purpose)

新実装（`src/tiasjudge/core/`）が旧実装と**同じ診断結果**を返すことを証明する（PLAN_01 成功基準・M1）．
そのために «同じ入力に対する旧 exe の出力» を固定データとして採取する．

## 採取方式の考え方 (Capture Design)

旧 exe には **RGB や L\*a\*b\* を直接入力する画面が無い**（`org/src` を確認済み）．
入力経路は「PNG 画像を読み込み → 画像上をクリック → その ROI の平均色」だけであり，
さらに**クリック位置を手作業で再現できない**という問題がある（PLAN_02 の注記）．

そこで次の方式で採取する．

- **画像全面を単一色で塗った PNG** を読み込ませる
  - ROI（51×51 px）がどこに置かれても平均色は画像の色そのものになる
  - → クリック位置が 1 px ずれても入力 RGB が変わらない＝再現可能な入力になる
  - → 入力 RGB は «画像を作るときに指定した R, G, B» として厳密に分かる
- 出力は 1 回の診断で **L\*a\*b\* と 5 色スコアの両方**をメイン画面から読み取れる
  - → 「RGB → Lab」と「RGB → スコア（パイプライン全体）」の 2 種類を同時に採取できる

※ 「Lab → スコア」を単独で採取することは，旧 exe に Lab の入力手段が無いためできない．
またメイン画面の L\*a\*b\* 表示は**整数に丸められている**ため，表示された Lab を入力として
使い回すと SVM の予測が変わりうる．したがって Lab は «出力側の照合対象» としてのみ扱う
（形式定義 README の ③ の注意を参照）．

## 事前準備 (Prerequisites)

1. 旧実装 exe を実行できる状態にする
   - 実行ファイル: `org/src/tonguediagnosisMFC2/x64/Release/tonguediagnosisMFC2.exe`（または Debug）
   - exe と同じ作業フォルダに **`data.csv`** と **`img/img_student2.bmp`** が必要
     （`org/src/tonguediagnosisMFC2/` 直下でそのまま実行するのが確実）
2. 撮影環境の **変換行列 CSV**（17 行 × 3 列）を 1 つ用意する
   - 実際の診断で使っているものを使う．どのファイルを使ったかを必ず控える
3. 採取用の単色 PNG を生成する（下記）

### 単色 PNG の生成 (Generate Solid-Color Images)

リポジトリ直下で次を実行する（生成先はリポジトリ外・作業用フォルダを推奨）．

```bash
uv run python scripts/generate_regression_images.py --out-dir <出力先フォルダ>
```

- 既定で 12 枚（代表的な舌色・境界値・域外色）を 1024×1280 px で生成する
- ファイル名は `rgb_156_102_098.png` のように **RGB がそのまま入る**（採取時の取り違え防止）
- 色を指定したい場合: `--color 156,102,98 --color 120,70,70`（複数指定可）
- 実行すると，採取表（CSV）の雛形が標準出力に表示される．そのままエディタに貼って使える

## 採取手順 (Capture Steps)

1 色（1 枚）につき次を 1 回行う．

1. 旧 exe を起動する
1. **① 変換行列(.csv)読み込み** の参照ボタンで変換行列 CSV を選ぶ
1. **② 舌画像(.png)読み込み** の参照ボタンで単色 PNG を 1 枚選ぶ
1. 左の画像表示エリアの**中央付近を左クリックする（1 点だけ）**
   - 「現在のクリック ●」が 1 つ点灯すれば OK
   - 画像の端から 15 px 以上内側をクリックする（端では ROI がはみ出して旧 exe が落ちる）
   - 誤ってクリックした場合は**右クリック**で取り消してから，読み込みからやり直す
     （※ 旧実装は右クリックしてもクリック数の内部カウントが戻らない．
     クリックし直したら一度 exe を再起動するか「診断続行」でリセットするのが安全）
1. **④ 舌色診断ボタン** をクリックする
1. **メイン画面の右下**に表示される次の 8 つの値を読み取り，採取表に記入する
   - 上から `紫 xx%`・`暗赤 xx%`・`紅 xx%`・`淡紅 xx%`・`淡白 xx%`
   - その下に `L* xx`・`a* xx`・`b* xx`
   - いずれも**整数表示**（旧実装の書式が `%3.0lf` のため．小数は表示されない）
1. 同時に開く**結果画面**を見て，赤い帯の **「Diagnosis failed / Please try again.」が出ているか**を記録する
   - 出ていれば `failed` 列に `yes`，出ていなければ `no`
1. 結果画面を閉じ，**診断続行** ボタンを押す
   - 「同じ変換行列を使用するか」に **はい** と答えると，変換行列を選び直さずに次の画像へ進める
1. 次の色の画像を ② から読み込み，同じ手順を繰り返す

### 採取すべきケース (Cases to Capture)

`scripts/generate_regression_images.py` の既定 12 色がそのまま以下をカバーする．
最低でも「代表色 5 点 + 境界値 2 点 + 域外 2 点」を採取する．

| 種類 | 色（R,G,B） | 意図 |
| --- | --- | --- |
| 代表 | 156,102,98 | 基準色（旧実装コメントの平均 BGR 由来） |
| 代表 | 180,120,115 | やや明るい舌色 |
| 代表 | 205,145,140 | 淡い舌色（淡紅・淡白寄り） |
| 代表 | 140,85,85 | やや暗い舌色 |
| 代表 | 115,62,68 | 暗い舌色（暗赤・紫寄り） |
| 代表 | 170,92,112 | 赤紫寄り |
| 代表 | 196,74,74 | 鮮やかな紅寄り |
| 代表 | 150,110,130 | 青み寄り |
| 境界 | 255,255,255 | 明るさの上限 |
| 境界 | 0,0,0 | XYZ が 0 にクリップされる（`L* = -16` になる想定） |
| 失敗 | 255,0,0 | 学習データ域外（「Diagnosis failed」が出るか確認する） |
| 失敗 | 0,0,255 | 学習データ域外 |

※ 実際の舌画像で «上位 2 色が入れ替わる境目» に近い色が分かっている場合は，
その前後の色も追加すると回帰テストの価値が上がる．

## 採取表の記入 (Recording)

生成スクリプトが出力した雛形を使い，**2 つの CSV** を作る．
列名・列の意味・許容誤差は [tests/fixtures/regression/README.md](../../tests/fixtures/regression/README.md) が正．

`tests/fixtures/regression/rgb_to_lab.csv`

```csv
matrix,r,g,b,l_star,a_star,b_star,note
translateMatrix.csv,156,102,98,55,22,7,基準色
```

`tests/fixtures/regression/rgb_to_scores.csv`

```csv
matrix,r,g,b,purple,dark_red,crimson,pink,pale,failed,note
translateMatrix.csv,156,102,98,16,61,11,5,0,no,基準色
```

記入のルール．

- 数値は**画面表示のまま**（整数）書く．四捨五入や桁の追加をしない
- 負の値（`a*` や `b*`）はマイナス記号を付けて書く
- `matrix` 列には使った変換行列 CSV の**ファイル名**を書く
- 使った変換行列 CSV 自体を `tests/fixtures/regression/matrices/` にコピーする（必須）
- 文字コードは **UTF-8**（Excel で保存する場合は「CSV UTF-8」を選ぶ）
- `#` で始まる行はコメントとして無視される（採取日・環境のメモに使ってよい）

## 照合の実行 (Run the Regression Test)

CSV を置いたら，リポジトリ直下で次を実行する（[ENV_04](../02_ENV/ENV_04_開発コマンド.md)）．

```bash
uv run pytest tests/test_regression.py -vv
```

- CSV が無い間は skip（理由に本手順書のパスが表示される）
- CSV を置くと 1 行 = 1 テストケースとして実行される
- 許容誤差（README と同じ）
  - L\*a\*b\*: 絶対誤差 **0.51 以内**（旧 exe が整数しか表示しないため）
  - 5 色スコア（%）: **完全一致**
  - 診断失敗の有無: **完全一致**

## 不一致だったときの扱い (When Results Differ)

**新実装（プロダクションコード）をその場で直さない**．次の順に切り分けて記録する．

1. 採取ミスの確認: 変換行列は同じか，クリックは 1 点か，画像を取り違えていないか
1. 差の大きさを確認: L\*a\*b\* が 1 未満のずれなら表示丸めの範囲内の可能性がある
1. 原因の記録: どの入力で・どの値が・どれだけずれたかを [PROGRESS.md](../PROGRESS.md) に追記する
1. 仕様への反映: 旧実装の挙動が SPEC_02 の記述と異なると分かった場合は SPEC_02 を更新してから実装を直す
   （PLAN_02 ステップ 5 の完了条件は「全ペアで結果一致（不一致時は原因を特定し記録）」）

## 精度を上げたい場合 (Higher Precision, Optional)

画面表示は整数までなので，L\*a\*b\* の照合はどうしても ±0.5 の幅を持つ．
より厳密に照合したい場合は，旧実装を Visual Studio で **Debug ビルド**して次を採取する．

- `CalcLab()` の直後に `TRACE("L=%.6f a=%.6f b=%.6f\n", m_tongueL, m_tonguea, m_tongueb);` を追加し，
  出力ウィンドウの値を `rgb_to_lab.csv` に書く（この場合は小数のまま記入してよい．
  テストの許容誤差 0.51 のままでも通るが，より厳しい照合が必要なら
  `tests/test_regression.py` の `LAB_DISPLAY_TOLERANCE` を下げる）
- 同様に `m_tongueL/a/b` に任意の値を代入してから `CalcSVM()` を呼ぶ改造版を作れば，
  「Lab → スコア」の組（README の ③ `lab_to_scores.csv`）も採取できる

※ 旧実装の改造は**参照専用の `org/` を書き換えない**（Git 管理外・原本保持）．
コピーを別フォルダに作って行うこと．
