# 判断ログ: これまで下した判断を transcript から読み出す

Issue: #997（#991 段階 1 の切り出し）

## 前提がひとつ変わった

#991 は「判断を記録する仕組みを作る」と書いていた。作る必要はなかった。**記録はもう存在している。**
Claude Code は `AskUserQuestion` を transcript に書いており、問い・ヘッダー・選択肢・各選択肢の説明・
選ばれた答えまで全部入っている。

このマシンの全 transcript を通した実測（7,357 ファイル / 7.5GB / 30.7 秒）:

| | |
|---|---|
| 判断（呼び出し） | 647 |
| 問い | 900 |
| 選択肢から選ばれた | 690 (77%) |
| 自由記述 | 120 (13%) |
| 答えが返らなかった | 90 (10%) |

だからこの PR は記録装置ではなく**読み出し**を作る。`GET /api/decisions?cwd=`。

## 何を残すか — 答えより「答えが選択肢に無かったこと」

`answerKind` を 3 値で持つのが設計の中心。

- `option` — 提示した選択肢から選ばれた
- `free-text` — **選ばずに自分で書いた**
- `unanswered` — 聞いたが答えが返らなかった

実データの自由記述は、質問を返す（「highlight.jsのテーマCSSって、多くの言語に対応している？」）、
前提を否定する（「いや、作業中のファイルがない限りは…」）、別のことを指示する、のいずれかだった。
これは**答えの情報ではなく、問いが間違っていたという情報**で、#991 の論点「学習の対象は『答え』では
なく『聞くべきかどうか』かもしれない」に直接効く。answer 文字列だけ貯めると、この 13% が
「変な答え」として他と混ざって消える。

`options[]` は label と description を両方残す。description には**選ばなかった方の帰結**が書いてある
——#991 が「判断に必要な情報」として挙げたもののうち、すでに書かれている唯一のもの。

## 読み取りは行ストリーム（一度書き直した）

最初は `fs.readFile(file, "utf8")` で書いた。実データで落ちた:

```
Error: Cannot create a string longer than 0x1fffffe8 characters
```

**585MB の transcript が実在する。** Node の文字列上限は約 512MB なので、内容と無関係に読めない。
`readline` で行ストリームにし、さらに `JSON.parse` の前に部分文字列でふるいをかける
（`AskUserQuestion` を含む行、または待っている tool_use_id を含む行だけ）。7.5GB を 30.7 秒で走る。

**同じ穴に既存コードが 7 箇所落ちている** — ロースター要約・コスト・タイムライン・タイトル。
どれも catch して「無い」と返すので、**一番長いセッションが一番情報の無いセッションとして表示される**。
これはこの PR の範囲外なので #998 に分離した。

## 境界

- 会話文の判断（「マージ」「ok 進めよう」）は取らない。構造化されていないので推測が要る。確実な方から
- Codex は取らない（rollout の形が違う）
- UI は次の PR。この PR は API まで
- 保存もしない。transcript が原本で、読めれば足りる。Claude Code が古い transcript を消し始めたら
  スナップショットが要るが、それは観測してから

## 上限

1 プロジェクトあたり mtime 降順で 200 ファイルまで、返却は既定 100 件（最大 500）。`scanned` を
レスポンスに入れて、**打ち切ったことが呼び出し側から見える**ようにする（黙って切ると「判断が少ない
プロジェクト」と区別がつかない）。(mtime, size) の memo 化は既存の `createFileCache` をそのまま使う。
実測: cold 119ms / cached 3ms。
