# 開発進捗ログ

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

- 最新エントリは下に追記する（時系列順．古いものが上，新しいものが下）
- CLAUDE.md の「開発進捗」セクションは最新 1 行のみ（上書き運用）
- 詳細・失敗パターン・設計判断はすべて本ファイルに残す
- 書式・運用ルールは .claude/rules/progress-log.md を参照
  （本ファイルの編集時に自動ロードされる）
-->

- [x] **プロジェクト立ち上げ（GUIDE_01）**: 要件定義・技術選定・環境構築・仕様設計・規約整備・開発計画を `chore/project-setup` で完了（2026-10-02）．solo モード
  - 動機: 舌診研究の各リポジトリが研究室 PC のフォルダを個別に読む形をやめ，データセット名と版で取り出せる共通の入口を作る
  - 設計判断: 目録は SQLite ＋ SHA-256 名のストア（取り込み時にコピー．原本参照より版の再現が確実）．計算サーバへは版ごとのバンドル（`SHA256SUMS` 付き）を直送．所見は種類の定義＋ JSON 値で持ち，種類の追加で表を作り直さない
  - 運用: 研究室 PC は手元 PC から `ssh labpc` で操作し，研究室 PC では編集しない．研究室 PC に uv 0.12.22・Python 3.12.15 を導入済み．検証プロファイルは作らない（CLI はテストと `tiasdata check` で確認する）
  - 未実装・後段: `main` がまだ存在しない（GitHub・GitBucket とも空）．取り込み後に研究室 PC へ clone する（ENV_02）．次は PLAN_02 Step 1
- [x] **舌色データが 1 患者 1 枚でないことの反映**: 研究室 PC の対応表（`DeepTIAS後_ID_番号.xlsx`）と件数だけで照合し，1085 枚が約 450 人分（2 枚以上の患者 239 人・874 枚）と判明（2026-10-03）．取り込みで対応表を読み，患者単位で症例をまとめる設計に直した（PLAN_01・PLAN_02・SPEC_01〜03・ENV_01）
  - 影響: TIASJudgeModel は画像 ID を `patient_id` にしており，同じ患者の画像が学習と評価に分かれている可能性がある．基盤経由に切り替える Step 8 で患者単位の分割に直し，成績の差を記録する
  - 判断: xlsx を読む openpyxl は任意の依存（`import`）にし，使う側には入れない
- [x] **研究室 PC の DeepTIAS 出力の整理**: 空き容量の不足（1.09 GB）を受け，舌色データセットで使った画像の DeepTIAS 出力だけを番号ごとのフォルダ `DeepTIAS_TIASJudgeModel\<番号>\` へ移し（同じドライブ内の移動．約 40.6 GB），使わない出力（約 8.1 GB）を削除した（2026-10-03．空き 9.5 GB）．元のデータは研究室のサーバにある
  - 方法: 対応表の xlsx（番号・何枚目・患者 ID）で引き，`2-cropped` × `3-resized` の作り直しが舌色データセットの画像と画素で一致するかで確認．対応表どおりで引けない 192 件（撮影日等の下位フォルダ・ID と合わないフォルダ名・何枚目の誤り等）は画素の一致で探して全件特定した．Claude は件数だけを見て，番号以外の名前・患者 ID は表示していない．移動・削除はユーザーが実行
  - 設計判断: 名前の規則を推測せず画素の一致を正とした（対応表の誤り 29 件を含めて確実に特定できるため）．`LabImg` × `4-mask` は撮影画像全体の大きさで，データセットの画像（枠の大きさ）とは一致しない
  - 発見: 同じ写真の重複が 5 組（PLAN_01「現在あるデータ」）．うち 2 組はラベルが違う．取り込み（Step 3）までに扱いを決める
- [x] **研究室 PC の臨床データを E ドライブへ移した**: 研究室 PC に E ドライブ（内蔵 SSD・約 465GB）ができたため，`C:\Users\Papin\clinical-data\` 全体（26,268 ファイル・45.30GB）を `E:\clinical-data\` へコピーし，SHA-256 と構成の照合の後に C 側を削除した（2026-10-06．C の空き 53.5GB）．docs・`.claude/repo-access.json`・`lab-pc-operation.md` のパスを書き換えた
  - 失敗パターン: C 側の削除が読み取り専用の属性が付いたフォルダで止まった（`shutil.rmtree` の WinError 5）．属性を外して再試行する `onexc` で解決．コピー済み・照合済みだったためデータの欠損は無し
  - 未実装・後段: TIASJudgeModel の手順書の原本のパスが古い．E ドライブの暗号化（BitLocker）は未定（ENV_03「人間が確認すべき事項」）
- [x] **PLAN_02 Step 1: 設定と目録の土台**: 設定ファイルの読み込み・検証，SQLite の目録と対応表のマイグレーション（SPEC_02 の全表と最初の種類），`tiasdata init` を実装（2026-10-06）
  - 設計判断: マイグレーションはリポジトリ直下ではなくパッケージ内（`src/tiasdata/catalog/migrations/`）に置く（サブモジュール・パッケージとして使ったときも見つけられるようにするため）．目録と対応表は別系列で版を管理する．凍結した版・所見の書き換え禁止，種類の整合，書式（日時は秒まで）を SQL の CHECK・トリガで強制する（SPEC_02「スキーマで強制する規則」）
  - 失敗パターン: ① SQLite の CHECK は NULL を違反としないため，`value_schema_version >= 1` が NULL ですり抜けた／② INTEGER 以外の主キーに NULL が入った → どちらも `IS NOT NULL`・`NOT NULL` を明示して解決．③ Windows でパイプ・SSH 越しの出力が cp932 で化けた → CLI の入口で標準出力・標準エラーを UTF-8 に切り替えた．④ `ruff format .` が docs/ の Markdown 内のコード例を整形した → `extend-exclude` に docs を追加
- [x] **PLAN_02 Step 2: ストア**: SHA-256 名のストアへの取り込み（一時ファイル → 照合 → 正式な名前）・点検用の照合と，テスト用のダミーデータ（舌色の 9 フォルダ構成）を実装（2026-10-06）
  - 設計判断: ストアのファイルは読み取り専用にする（誤操作対策．「直したい」場合も書き換えず，新しいファイル・所見の訂正・新しい版で扱う．本当に消す場合は将来の専用コマンドで記録を残して消す）．store フォルダが無ければ作らずに止める．同じ中身で拡張子が違うファイルは Step 3 の取り込みで止める
  - 追加の判断: 既にあるファイルを再利用したとき（同じ中身を再び取り込んだとき）も読み取り専用を付け直す（バックアップからの復元・手作業等で属性が外れたファイルを守り直すため）．取り込みで触らないファイルの属性は，Step 3 の `check` で書き込み可能なファイルの数として報告する
  - 未実装・後段: POSIX（os.link）の分岐は Windows では未検証
- [x] **舌色データセットの重複 5 組の扱いを決めた**: 基盤では正解を推測で決めず，確かめられるまで保留にする（2026-10-06）．保留リスト `holds/tiasjudgemodel.toml` に 9 枚（122・184・548・566・381・382・515・516・509）を載せ，取り込みで飛ばして件数を報告する（SPEC_03「保留リスト」）．508/509 は DeepTIAS の出力と完全一致する 508 を残す
  - 未実装・後段: 122/184・548/566 は研究室のサーバの元のデータで患者を，381/382・515/516 は評価者にラベルを確かめる
- [x] **PLAN_02 Step 3: 取り込みと点検**: 舌色の 9 フォルダ＋対応表 xlsx の取り込み（患者ごとに症例・画像ごとに撮影，患者 ID は対応表 DB にだけ，保留リストの番号は飛ばす），`tiasdata import`・`stats`・`check` を実装（2026-10-06）
  - 設計判断: 目録と対応表は別 DB だが，対応表を ATTACH して 1 トランザクションで登録する（失敗時はどちらにも残らない．ストアにコピー済みのファイルは残り，check が報告し次の取り込みで再利用）．書き込みの前に構成・保留・対応表・同じ中身の重複をすべて検証する．保留リストはリポジトリの `holds/` をパッケージの位置から辿って読む
  - ユーザー判断: 対応表で番号が整数でない行は使わず件数を報告する（実データに 1 行あるため．停止だと取り込めない）．保留リストのファイルが無い取り込み元は停止する（空のリストを置く）
  - 未実装・後段: テスト全体の実行が約 70〜80 秒に延びた（取り込みの停止 18 種 × 2 通り）．必要なら取り込み済みの状態を fixture で共有して短くする
- [x] **PLAN_02 Step 4: データセットと版**: データセットの定義（`datasets/tongue_color.toml`），定義の当てはめと版の作成（freeze），manifest.csv の生成（純関数），`tiasdata dataset list`・`show`・`freeze`，check での全版の manifest の照合を実装（2026-10-06）
  - 設計判断: 版は「定義の全文＋採用したファイルと所見の行」が直前と同じなら作らない（同じ値への訂正でも新しい版）．版の行は manifest の SHA-256 を計算してから 1 トランザクションで INSERT（凍結のトリガがあるため UPDATE しない）．未コミットの変更があると作らない．種類との照合は作るときだけ（過去の版の作り直しに使わない）
  - 未決: 版が参照するファイルの種類（`assets.kind`）や撮影の症例（`captures.subject_id`）は書き換えられ，書き換えると過去の版の manifest が変わる（check は不一致として見つける）．書き換えをトリガで禁止し，症例の誤りは訂正の行で直す仕組みにするかを決める（保留中の 122/184 の患者の確定で関係する）
- [x] **PLAN_02 Step 5: バンドル**: 凍結した版のバンドルの書き出し（`tiasdata export`．`export.py`）と，目録に依存しない読み込み・検証（`tiasdata.load`・`open_bundle`・`Bundle.verify`・`fingerprint`．`bundle.py`）を実装（2026-10-08）
  - 設計判断: 読み込みと書き出しをモジュールで分け，`import tiasdata` で目録まわり（catalog・store・config・sqlite3）を読み込まない（計算サーバで使うため）．共有する純関数は `manifest.py` に集めた．`dataset.json` に書き出した日時を入れず同じ版から同じバイト列にする（既存のバンドルをバイト単位で照合できる）．バンドルは読み取り専用にしない（作り直せて消す前提）．`load` の版はキーワード必須．エラーにバンドルの場所を出さない
  - 未実装・後段: `BundleRow.annotations` の入れ子の値が書き換えられる（使う側の誤りを防ぐなら読み取り専用にする）．書き出しに失敗すると空の `bundles/<名前>/` が残る（害はない）
- [x] **編集の扱いを決めた**: 操作は Claude に指示して行う運用なので，ラベル・患者・ファイルの情報は編集できるようにし，破壊的な編集（過去の版の中身が変わる・データが消える）のときは実行前に警告してユーザーが決める方針にした（2026-10-08）．凍結した版の記録そのものは今までどおり書き換え禁止
  - 判断: 当面は今の形のまま運用する（症例・撮影・ファイルの表はスキーマ上は書き換えられ，書き換えると check が過去の版の manifest の不一致として見つける）．編集のコマンド（試走・破壊的の判定・履歴）は必要になった時点で作る（PLAN_02「マイルストーン 2 以降の候補」）．Claude は目録を SQL で直接編集しない（lab-pc-operation）
  - これで Step 4 の未決（assets・captures の書き換えを禁止するか）は「禁止せず，編集のコマンドと警告で扱う」に決着
- [x] **要確認リストとバックアップ**: 先生から受け取った 1085 枚を問題のあるものも含めて全部目録に入れ，問題には後で対応する方針にした（2026-10-08．ユーザー判断）．保留リスト（`holds/`．飛ばす）を要確認リスト（`reviews/`．印を付けて取り込む）に変え，所見の種類 `review`（catalog/0002）を追加．同じ中身ですべて要確認の番号は，ファイルを 1 つだけ撮影にひも付けずに登録する．データセットは撮影にひも付かないファイルを除いて件数を報告する．あわせて `tiasdata backup`（目録と対応表をそれぞれの backups に複製・integrity_check）を実装
  - 設計判断: 要確認の印の付いた撮影も版に入れる（版 1 は 1081 枚の見込み）．患者が食い違う同じ中身の 2 組（122/184・548/566）は患者を作らず版に入らない．登録済みに印を足すのは書き足すだけ．対応表のバックアップは対応表のフォルダに置く（目録と分けるため）
  - 研究室 PC の手順: `git pull` → `uv sync --no-dev --extra import` → `tiasdata init`（0002 を適用）→ `tiasdata import tiasjudgemodel`（既存 1076 枚は飛ばし 9 枚を追加）→ `check`・`stats` → 版 1 → `backup`
  - 未実装・後段: `importers/tongue_color_folders.py` が約 1000 行（走査・計画と照合・登録でモジュールを分けるとよい）．別の媒体への退避は未定．書き出し先のパスが Windows の上限（260 文字）を超えると export がスタックトレースで落ちる（研究室 PC のパスでは当たらない見込み）
