# feat #910 Phase 3 — 開いているファイルが外で変わったことに気づく

409 は「保存しようとした瞬間」に教えてくれる。その前に知りたい。

## 2 つ用意する理由

| 層 | 速さ | 守備範囲 |
|---|---|---|
| **PostToolUse hook** | 即座 | **Claude だけ** |
| **30 秒ポーリング** | 遅い | 全部（Codex・git・ビルド・他のエディタ） |

Codex は hook を出さない（rollout ファイルのポーリングで活動を検知する別系統）。逆にポーリングが
あるので hook は取りこぼしてよく、hook があるのでポーリングは 30 秒でゆるくできる。

**`fs.watch` は使わない。** cwd がターミナルごとに散っているので watcher を共有できず、
`server/session/codex-activity-watch.ts` の precedent — Windows で 8.3 短縮パスに watch を
張ると libuv がプロセスごと abort する — がある。

## hook 側は既にあった

`dirConfigWriteTarget()` が「書き込み系ツール ＋ `file_path` ＋ セッション cwd で解決」を
やっていて、`.mulmoterminal.json` に絞っていただけ。**一般形 `writtenFilePath()` を
`server/files/tool-writes.ts` に出し、`dirConfigWriteTarget` はその絞り込みとして書き直した** —
設定のライブリロードとエディタの変更検知が別々に育たないように。

## 気づいたら何をするか

| バッファ | 反応 |
|---|---|
| きれい | **黙って読み直す**。ペインが「生きたビュー」として振る舞う |
| 編集中 | **バナーを出す**（409 と同じもの）。ユーザーの代わりに選ばない |

## ポーリングの中身

`GET /api/files/browse/version` を足した。`/text` を叩くと 16 文字の答えのためにファイル全部が
流れる。開いているファイル 1 つにつき 30 秒に 1 回の stat + hash。

## テスト

- 一般形（サーバ 5 件）— 書き込み系ツールだけ拾う / 相対パスはセッション cwd で解決し、
  cwd が無ければ何も言わない / `dirConfigWriteTarget` の絞り込みが保たれている
- version ルート（2 件）— `/text` と同じ version を返す / 無いファイルは `null`
- 突き合わせ（クライアント 6 件）— 別ファイル・別プロジェクトは無視 / **区切り文字と大小文字**の
  違いを吸収（取りこぼすより余計に 1 回確認する方が安い）
- ペイン（3 件）— きれいなら黙って差し替え / 編集中はバナーでバッファ不変 / 同じ version なら何もしない
