yoi/tickets/persistence-semantics.md

97 lines
5.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 永続化層のセマンティック整理
## 背景
現在の永続化は `SessionId` 単位の append-only JSONL log を中心に構成されている。これは実装上は扱いやすい一方で、今後 Pod 単位永続化、compaction、fork、DB backend 追加などを進めるにあたり、以下の概念が混ざり始めている。
- ユーザー視点の「同じ会話 / 作業の継続単位」
- Pod 視点の「現在 active な会話状態」
- append-only log の物理的 / 復元上の単位
- compaction によって生成される新しい履歴系列
- fork の起点となる履歴中の境界
- runtime dir に置かれる一時状態と、data dir / DB に置く永続正本
特に、現在は compaction によって新しい `SessionId` が発行される。これは append-only log の低レベル単位としては自然だが、ユーザー視点では「同じ会話が継続している」とも見えるため、`Session` という名称・粒度が今後の設計上あいまいになり得る。
このチケットでは、実装変更に入る前に、永続化層のドメイン概念・名称・責務境界を整理する。
## 目的
- 永続化層で扱う概念を、ユーザー視点 / Pod 視点 / storage 視点に分けて定義する。
- `SessionId` が今後も適切な中心概念か、あるいは別概念に分解すべきかを判断する。
- compaction / fork / resume / Pod state / spawned child registry が、どの粒度のデータに属するかを決める。
- 将来 DB backend を追加しても歪みにくいデータ構造を設計する。
- 既存の session-store JSONL 実装から段階的に移行できる命名・API 境界を決める。
## 検討事項
- 会話継続単位と append-only log 単位を分けるべきか。
- 例: user-visible conversation/thread と、internal log segment の分離。
- compaction の扱い。
- compaction 後の履歴を新しい低レベル log として扱うのは自然か。
- その場合、ユーザー視点では同じ会話の継続としてどう表現するか。
- fork の扱い。
- fork は新しい会話単位を作るのか、同一会話内の branch とするのか。
- fork 起点を entry hash / turn boundary / checkpoint など、どの抽象度で表すか。
- Pod state の責務。
- Pod 名から active な会話 / log を復元するために何を持つべきか。
- Pod が過去に辿った session / log の順序付き履歴をどこに持つべきか。
- runtime state と persistent state の境界。
- `history.json` / `status.json` / `spawned_pods.json` を永続正本として扱わない方針の確認。
- session log の `pod.scope` extension entry を撤廃するか(要検討)。
- 現状: session log に `PodScopeSnapshot` を extension として append し、session 復元時に scope も復元できる。
- Pod 単位永続化(`tickets/pod-persistent-state.md`が入ると、scope の正本を Pod state に持つほうが責務が明確で、session log との重複も解消できる。
- ただし scope は session 内で動的に変化し得るため、「最新 snapshot は Pod state 」「変化履歴は session log の event として残す」のような分割もあり得る。conversation timeline 上の scope 変化を session 単独で再現する必要があるかが論点。
- 撤廃の選択肢: (a) session log から完全に削除し Pod state を唯一の正本にする / (b) snapshot 保持責務だけ Pod state に寄せ、scope 変更 event は session log に残す / (c) 現状維持で Pod state は session への参照のみ。
- DB backend を想定した場合のテーブル / relation 相当の構造。
- append-only entry log
- lineage / origin
- active pointer
- Pod / child Pod registry
- index / listing / GC の余地
- 既存 API / CLI 名称の移行方針。
- `--session` の扱い
- debug 用 ID とユーザー向け ID の分離
## 一案: Thread / Segment / Checkpoint に分ける案
これは現時点の決定ではなく、検討材料の一案として置く。
- `Pod`: agent 実行主体 / process identity。
- `Thread`: ユーザー視点の会話・作業継続単位。compaction しても同じ Thread と見なす。
- `Segment`: append-only log の物理的 / 復元上の単位。現在の `SessionId` に近い。compaction / fork で新しい Segment が生まれる。
- `Entry`: Segment 内の 1 永続化イベント。
- `Checkpoint`: fork / rollback / UI 選択などの起点を表す抽象境界。内部的には Segment + EntryHash を指してもよいが、表層 API では entry pointer を直接露出しすぎない。
この案では:
- compaction = same Thread, new Segment
- fork = new Thread または branch, new Segment
- resume = same Thread の active Segment に append
- Pod state = active Thread / spawned children / 必要な runtime 復元メタデータを保持
- lineage = Segment origin または Checkpoint reference として保持
この案を採用するかは本チケット内で改めて比較・判断する。
## 完了条件
- 永続化層の主要概念と名称が文書化されている。
- compaction / fork / resume / Pod state のデータ粒度が決まっている。
- 現在の `SessionId` / session-store API をどう扱うか、維持・alias・rename・段階移行の方針が決まっている。
- DB backend を追加する場合の概念モデルが、最低限テーブル / relation 相当で説明できる。
- `tickets/pod-persistent-state.md` や fork 関連チケットに反映すべき前提が整理されている。
## 範囲外
- このチケット単体での大規模 rename 実装。
- DB backend の実装。
- UI の履歴表示 / branch 表示の詳細 UX。
- GC / retention policy の実装。
## 関連
- `tickets/pod-persistent-state.md`
- `tickets/pod-session-fork.md`
- `crates/session-store/`
- `crates/pod/src/pod.rs`