# テスト妥当性レビュー: session-store
- 評価: 概ね良い

## 確認範囲

- `crates/session-store/README.md`
- `crates/session-store/Cargo.toml`
- `crates/session-store/src/`
  - `lib.rs`
  - `store.rs`
  - `fs_store.rs`
  - `segment.rs`
  - `segment_log.rs`
  - `logged_item.rs`
  - `system_item.rs`
  - `event_trace.rs`
- `crates/session-store/tests/`
  - `fs_store_test.rs`
  - `session_test.rs`
  - `common/mod.rs`
- 実行確認: `cargo test -p session-store`

## 現在のテストがよくカバーしていること

`session-store` の主要責務である「append-only JSONL session log を読み書きし、Worker 復元用 state に replay する」部分は、短時間レビューとしては十分に押さえられています。

良い点:

- `collect_state` の基本 replay が広くテストされている。
  - 空の log
  - `SegmentStart`
  - user / assistant / tool call / tool result
  - `TurnEnd`
  - `ConfigChanged`
  - `LlmUsage`
  - `Invoke` marker が state を変えないこと
  - `Extension`
  - typed `protocol::Segment` の保存と flattened user message への復元
- `LoggedItem` の stable mirror が比較的よく検証されている。
  - message
  - tool call
  - tool result content / error flag
  - reasoning encrypted content
  - reasoning signature
  - legacy signature 欠落 JSON
  - serde tag shape
- `SystemItem` は、LLM に入る `history_text` が stored body 由来であること、reminder wrapping、legacy default source、JSON round-trip が確認されている。
- `FsStore` は tempfile を使った実 FS の読み書きで確認されている。
  - append / read round-trip
  - `create_segment`
  - `list_sessions`
  - `list_segments`
  - `exists`
  - missing segment
  - trace file が segment log と分離されること
  - `read_entry_count`
  - `lookup_session_of`
- `session_test.rs` は mock LLM + actual `agen::Worker` を通して、単純応答・tool call・pause・restore・fork 系を実行している。単なる pure unit だけでなく、crate 境界上の使われ方もある程度守れている。
- fork lineage について、fresh-session fork / in-session `fork_at` / live conflict `ensure_head_or_fork` / nested past fork まで触れているのは良いです。特に「source segment を mutate しない」方針をテストで固定できています。

## 不足・疑問のあるテスト

現状は「基本機能の回帰検出」としては強い一方で、session-store の重要 invariant に対して未検証の穴がいくつか残っています。

- `create_compacted_segment` が未テスト。
  - この crate の説明上、compaction は fork と並ぶ segment lineage 操作です。
  - `compacted_from`、同一 `session_id` 継承、seed history/config/system prompt の保存が直接検証されていません。

- `Store::truncate` が未テスト。
  - trait default 実装で `read_all -> truncate -> create_segment` するため、empty-turn rollback などの重要用途で壊れてもこの crate 単体では検出しにくいです。
  - `entries_len > len` の `StoreError::Corrupt` も未検証です。

- corrupt JSONL の扱いが未テスト。
  - `FsStore::parse_jsonl` は blank line を無視し、serde failure を `StoreError::Corrupt { line, message }` に変換します。
  - line number、blank line skip、部分的に壊れた file で read が fail closed することは永続ログ store として重要ですが未確認です。

- `FsStore` の filtering / layout invariant が一部弱い。
  - top-level old flat files を `list_sessions` が無視すること。
  - invalid UUID directory を無視すること。
  - `.trace.jsonl` を `list_segments` が segment として拾わないこと。
  - invalid segment filename を無視すること。
  - `list_segments` の newest-first order は `contains` 中心で、順序を強く確認していません。

- `save_delta` / `classify_history_item` の直接テストが薄い。
  - user message を skip する contract は integration helper 経由では使われていますが、直接の単体テストがありません。
  - reasoning が `AssistantItem` になること、tool result error/content が `ToolResult` として保存されること、unknown/future-ish branch の defensive behavior は十分固定されていません。

- `RunErrored` path が未テスト。
  - `run_and_persist` helper には error branch がありますが、最後に `result.unwrap()` するため、実際には error persistence の検証に使えません。
  - `save_run_errored` と replay 時の `last_run_interrupted` 反映は、失敗 turn の session 復元に関わるため追加価値が高いです。

- `SystemItem` の replay path が直接弱い。
  - `SystemItem::history_text` 自体はテストされていますが、`LogEntry::SystemItem` を `collect_state` したときに `Item::system_message` へ入ること、`append_system_item` 経由で store に保存されることは明示的にテストされていません。

- fork 系の一部 assertion が弱い。
  - `session_fork_at_truncates_within_session` は fork state と source-at-fork の `history.len()` だけを比べています。content / item kind / config / system prompt / lineage まで比較した方が妥当です。
  - `at_turn_index == 0` を、実際に turn 後の source segment に対して使うケースが薄いです。
  - 存在しない `at_turn_index` の扱いは未固定です。現実装は `unwrap_or(entries.len())` で末尾 fork になりますが、それが意図かどうかをテストで明確にした方がよいです。
  - `ensure_head_or_fork` の no-op branch（count equal）と、store count が writer tally より小さい場合の policy が未検証です。

- integration tests の一部は smoke test 寄りで、壊れ方を見逃しやすい。
  - `session_restore_round_trip` は history の長さだけで、復元 item の content / role / tool call id までは比較していません。
  - `session_run_with_tool_call` は `ToolResult` / `AssistantItem` の存在だけを確認しており、順序・call id・tool result content・final assistant text を見ていません。
  - `session_run_logs_entries` はコメントでは最低 5 entry と書きつつ `>= 4` で、`UserInput` の存在も明示確認していません。

- real concurrency / append atomicity は未テスト。
  - この crate は append-mode JSONL を concurrency 境界として扱っていますが、複数 clone / thread からの append が line corruption しないことは未確認です。
  - ただし OS/filesystem 依存が強いので、軽い regression test に留めるのが妥当です。

## 追加を提案するテスト

優先度順に追加するなら以下です。

1. `create_compacted_segment` の lineage test
   - source session を作る
   - compacted segment を作る
   - first entry が `SegmentStart { session_id: source_sid, compacted_from: Some(...) }`
   - `forked_from` は `None`
   - history/config/system prompt が seed state から復元される

2. `Store::truncate` default behavior test
   - 3〜4 entries を作る
   - 2 entries に truncate
   - `read_all` が prefix のみ返す
   - `read_entry_count` が一致する
   - len 超過 truncate が `StoreError::Corrupt` になる

3. corrupt JSONL test
   - tempfile 上に直接 invalid JSON line を置く
   - `read_all` が `StoreError::Corrupt { line, .. }` を返す
   - blank line が count / parse に影響しないことも併せて確認する

4. `FsStore` layout filtering test
   - root 直下の `<uuid>.jsonl` を無視
   - invalid directory を無視
   - session dir 内の `<segment>.trace.jsonl` と invalid filename を `list_segments` が無視
   - segment order を newest-first で assertion

5. `save_delta` direct unit/integration test
   - input に user message / assistant message / reasoning / tool call / tool result を混ぜる
   - user message が保存されないこと
   - classification と order が期待通りなこと

6. `RunErrored` persistence test
   - `save_run_errored` を直接使うだけでもよい
   - 可能なら mock client error を発生させ、Pod 相当の persistence sequence で `RunErrored` が書かれることを確認する
   - `collect_state` / `restore` で `last_run_interrupted` が反映されることを確認する

7. `SystemItem` replay/store test
   - `append_system_item` で notification / task reminder などを保存
   - `restore` 後の `history` に `role: system` の message と stored body が入ることを確認する

8. fork tests の assertion 強化
   - `history.len()` だけでなく、復元 content / role / item kind を比較する
   - `forked_from` の `segment_id` と `at_turn_index` を `fork_at` test でも確認する
   - `at_turn_index == 0` on non-empty source と nonexistent turn index の policy を固定する

## 実行したコマンド

```sh
cd /home/hare/Projects/yoi && cargo test -p session-store
```

結果:

- unit tests: 29 passed
- `tests/fs_store_test.rs`: 8 passed
- `tests/session_test.rs`: 9 passed
- doctest: 1 ignored
- overall: passed

