summaryrefslogtreecommitdiff
path: root/docs/architecture.md
blob: 64d4b0654429317aae680f1dbab2d8eb4cbf31c6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
# Architecture

設計項目ごとの実装・テスト状況は
[設計・実装・テスト状況一覧](implementation-status.md)を参照してください。

`tiny-convmem-mcp` is a single-process C17 MCP server backed by a
durable append-only conversation log. The executable owns the stdio dispatch
boundary and uses mcpc's bundled mjson parser through a local compatibility
layer.

Conversation-memory work is split into these dependencies:

```text
MCP transport and tools  ->  domain contracts  <-  storage adapters
```

- `src/mcp` translates MCP requests and responses. It may depend on mcpc and
  domain contracts, but it must not contain persistence logic.
- `src/domain` owns conversation and message concepts without depending on
  mcpc or a database.
- `src/storage` implements the versioned binary log, recovery, snapshot, and
  compaction through the platform-neutral `src/sys` API.
- `src/sys` owns UTF-8 path conversion, files, process locks, durable flush,
  clocks, and random bytes. Its implementation is the only platform split.

## Implemented prototype contract (v1)

The six public tools are `write_message`, `read_messages`, `search_messages`,
`delete_message`, `rebuild_index`, and `get_system_health`. The detailed
"ProtoType Architecture v0.0.1" below is retained as the original proposal;
where it conflicts with this section, the implemented contract is authoritative.

- `write_message` creates the ULID and UTC millisecond timestamp. A PUT or DEL
  succeeds only after the platform durability flush succeeds.
- Deletion is immediately invisible but remains a tombstone until synchronous
  compaction. `metadata.deleted` is not part of immutable Message data.
- Metadata is limited to optional `tool_call_id`, `tags`, and `memory_tier`.
  Tiers are labels only; no automatic lifecycle operation is performed.
- Search uses ASCII-case-folded Unicode codepoint 2/3-grams, verifies hash
  matches against the original codepoints, and ranks exact substrings first.
- A log record contains magic, format version, type, payload length, sequence,
  and payload CRC32. PUT, DEL, and generation marker records are supported.
- A valid snapshot contains immutable messages and a log generation/offset.
  Startup loads it only when the active log generation matches, then replays the
  tail. Otherwise startup performs a full log replay.
- An incomplete final record is truncated. Unknown versions/types, invalid
  lengths, non-monotonic sequences, or CRC errors within a complete record stop
  startup without silently skipping data.
- `--data-dir <path>` is mandatory and guarded by a process-exclusive lock.

The prototype remains Windows x64/MSVC and single-process. Retention,
encryption, search pagination, multiple writers, automated summarization, and secure
physical erasure are outside v1.

# ProtoType Architecture v0.0.1
Tiny-ConvMem-MCP: FINAL TOOL INTERFACE SPECIFICATION (v1.0)

この定義は、システムと外部(LLMプロセス)との間の「契約書」となります。これで実装に着手できますね!
No. 	Tool Name 	カテゴリ 	機能概要 	入力引数 (Arguments) 	出力値 (Response)
1 	write_message 	SET/WRITE 	新しいメッセージイベントをログファイルへ追記し、インデックスを更新する。 	session_id, role, content, timestamp 	status: Enum(OK, ERROR)
2 	read_messages 	GET/READ 	特定セッションIDのメッセージを安定順序でページ取得する。 	session_id、limit、cursor 	history、nextCursor
3 	search_messages 	GET/READ 	クエリに基づいてログファイルから関連するメッセージを特定し、返す。(インデックス利用が前提) 	query, session_id (任意), limit: 整数 	results: 配列(メッセージオブジェクト)
4 	delete_message 	SET/MANAGE 	特定のメッセージIDを指定してログから完全に削除し、インデックスをクリーンアップする。 	message_id: 唯一ID, session_id (任意) 	status: Enum(OK, NOT_FOUND)
5 	rebuild_index 	SET/MANAGE 	インデックスファイルを再生成し、データ整合性を回復させる。(メンテナンス) 	なし 	status: Enum(OK, ERROR)
6 	get_system_health 	GET/READ 	システムの稼働状況とログファイルの健全性レポートを提供する。 	なし 	report: JSON (ヘルスステータス)


データ構造設計:メッセージオブジェクト (Message Object Definition)
🎯 基本方針

全てのデータは**「不変(Immutable)」**であることを原則とします。一度記録されたイベントは変更せず、削除が必要な場合は新しいエントリで処理するか、専用の delete_message コマンドで対応します。
📝 メッセージオブジェクト (Message) の構造定義案

メッセージを構成する要素を分解し、データ型を明確に定義します。(C++でのStructやJSONスキーマとして使用できます)

{
  "message_id": "UUID/ULID文字列", // ★最重要。削除・参照のユニークキー
  "session_id": "ユーザー固有のセッション識別子",
  "timestamp": 1720843200000, // UTCミリ秒タイムスタンプ (UTC厳守)
  "role": "ENUM (user | assistant | system)", // メッセージの発信元
  "content": "メッセージの本文(テキストデータ)", // 記録したい主要な情報
  "metadata": { // 追加情報格納用。拡張性を持たせるための辞書型
    "tool_call_id": "もしこのメッセージがツール呼び出しの結果ならIDを保持",
    "is_system_message": true/false, // システム操作やプロンプト定義など
    "checksum": "(オプション)データの完全性を保証するためのハッシュ値"
  }
}

⚙️ 補足的なデータ構造の定義

ログシステムをより堅牢にするために、メッセージとは別に必要な型も定義しておくと完璧です。

    LogEntry (永続化層の最小単位):
        実際にディスクに書き込まれる最も小さいデータ単位。(上記 Message のバイナリ/JSON表現)
    SearchIndexEntry (インデックス構造体):
        検索効率を最大化するための、非常に軽量なメタデータ。
        message_id: どのメッセージかを示すキー
        session_id: 属するセッションID
        keywords_hash: メッセージ内容から抽出されたキーワードのハッシュ値(またはリスト)
        file_offset: ログファイル内での物理的な開始位置
        data_size: そのメッセージが占めるバイトサイズ

📐 Tiny-ConMem-MCP: ストレージ制御 統合設計仕様
1. アーキテクチャ概観

┌─────────────────────────────────────────────────────────────┐
│                    外部プロセス (LLM Host)                    │
└──────────────────────────┬──────────────────────────────────┘
                           │ stdio (JSON-RPC)
┌──────────────────────────▼──────────────────────────────────┐
│              L1: Protocol Layer (mcpc)                       │
│              MCPメッセージの受信・ツールディスパッチ             │
└──────────────────────────┬──────────────────────────────────┘
                           │
┌──────────────────────────▼──────────────────────────────────┐
│              L2: Memory Core (ビジネスロジック)                │
│                                                             │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐          │
│  │ Write Queue  │  │ In-Memory   │  │ Search     │          │
│  │ (保留中キュー) │  │ Index      │  │ Engine     │          │
│  └──────┬──────┘  └──────┬──────┘  └──────┬──────┘          │
│         │                │                │                  │
└─────────┼────────────────┼────────────────┼──────────────────┘
          │                │                │
┌─────────▼────────────────▼────────────────▼──────────────────┐
│              L3: Persistence Layer (永続化層)                  │
│                                                             │
│  ┌──────────┐  ┌────────────┐  ┌───────────────────┐        │
│  │ active.log│  │snapshot.bin│  │ compaction worker │        │
│  │(append-   │  │(状態保存)   │  │(ログ整理・容量削減) │        │
│  │  only)    │  └────────────┘  └───────────────────┘        │
│  └──────────┘                                               │
└─────────────────────────────────────────────────────────────┘

2. データ構造定義
2.1 Message Object(永続化対象の基本単位)

全ツールの入力・出力の中心となるデータです。一度書き込まれたら不変(Immutable)で、変更は新エントリの追記で表現します。

// Message (ログ1レコードの論理構造)
{
  "message_id":  "ULID文字列",          // 削除・参照のユニークキー
  "session_id":  "セッション識別子",      // セッション単位のグルーピング
  "timestamp":   1720843200000,          // UTC ミリ秒
  "role":        "user | assistant | system",
  "content":     "メッセージ本文",
  "metadata": {
    "tool_call_id":  "(任意)ツール呼び出しID",
    "tags":          ["カレー", "設計"],   //(任意)検索用タグ
    "memory_tier":   "short | mid | long", // 後述のメモリ階層フラグ
    "deleted":       false                // 論理削除フラグ
  }
}

2.2 LogRecord(ディスク上の物理フォーマット)

active.log に追記される物理レコードです。Message Object をシリアライズしたものに、検証用のメタ情報を付加します。

┌──────────┬──────────┬─────────────────────┬──────────┐
│ record   │ payload  │ payload (serialized │ checksum │
│ length   │ type     │  Message Object)    │ (CRC32)  │
│ (4 byte) │ (1 byte) │ (可変長)             │ (4 byte) │
└──────────┴──────────┴─────────────────────┴──────────┘

payload_type:
  0x01 = PUT     (メッセージの書き込み)
  0x02 = DEL     (メッセージの論理削除)
  0x03 = SNAPSHOT_MARKER (snapshot境界マーカー)

2.3 In-Memory Index(メモリ上のインデックス)

メモリ上に保持する高速検索用の目次です。これが SearchIndexEntry の実体で、search_messages / read_messages の高速化を担います。

struct IndexEntry {
    uint64_t    file_id;       // ログファイル識別子 (1 = active.log 等)
    uint64_t    offset;        // レコードの開始バイト位置
    uint32_t    length;        // レコード長
    int64_t     timestamp;     // メッセージのタイムスタンプ
    uint8_t     type;          // PUT / DEL
    // セッションID・メッセージID は
    // ハッシュテーブルの Key として使用
};

// メモリ上のデータ構造(ハッシュテーブル + リスト)
HashTable<message_id,   IndexEntry*>   // message_id → 位置情報
HashTable<session_id,   List<message_id>>  // session_id → 所属メッセージ一覧
HashTable<keyword_hash, List<message_id>>  // 検索用キーワード逆引き

3. 書き込みパイプライン(write_message / delete_message)

┌─────────────┐
│ MCP Tool 呼出 │  write_message / delete_message
└──────┬──────┘
       │
       ▼
┌─────────────────────┐
│ Step 1: メモリ更新    │  In-Memory Index に即座に反映
│                     │  (PUT → 追加, DEL → フラグ更新)
└──────┬──────────────┘
       │
       ▼
┌─────────────────────┐
│ Step 2: キュー追加    │  Write Queue に LogRecord を積む
└──────┬──────────────┘
       │
       ▼
┌─────────────────────┐
│ Step 3: バッチ書き込み │  flush_interval_ms (1000ms) または
│                     │  max_pending_records (128件) に
│                     │ 達したら write() で一括追記
└──────┬──────────────┘
       │
       ▼
┌─────────────────────┐
│ Step 4: 定期 fsync   │  fsync_interval_ms (5000ms) ごとに
│                     │  fsync() でディスクに確実に落とす
└─────────────────────┘

設計パラメータ:

#define FLUSH_INTERVAL_MS    1000   // キュー→ファイルの書き出し間隔
#define FSYNC_INTERVAL_MS    5000   // fsync() の実行間隔
#define MAX_PENDING_RECORDS  128    // キューの最大保留件数

4. 読み込みパイプライン(read_messages / search_messages)

┌─────────────┐
│ MCP Tool 呼出 │  read_messages / search_messages
└──────┬──────┘
       │
       ▼
┌─────────────────────┐
│ Step 1: インデックス  │  In-Memory Index から該当レコードの
│      検索           │  (file_id, offset, length) を取得
└──────┬──────────────┘
       │
       ▼
┌─────────────────────┐
│ Step 2: pread()     │  ログファイルの該当オフセットのみ
│      部分読み出し     │  pread(fd, buf, length, offset)
│                     │  ※ログ全体は読み込まない
└──────┬──────────────┘
       │
       ▼
┌─────────────────────┐
│ Step 3: デシリアライズ│  LogRecord → Message Object に復元
│                     │  deleted フラグを確認し、
│                     │  削除済みなら除外
└──────┬──────────────┘
       │
       ▼
┌─────────────────────┐
│ Step 4: レスポンス   │  JSON配列として MCP 経由で返却
│      返却           │
└─────────────────────┘

5. 起動時復旧シーケンス

プロセス起動
    │
    ▼
┌──────────────────┐
│ Step 1:           │
│ snapshot.bin 読込  │  最後のスナップショットから
│                  │  In-Memory Index を復元
└──────┬───────────┘
       │
       ▼
┌──────────────────┐
│ Step 2:           │  snapshot 作成時点以降の
│ ログ再生          │  active.log を先頭から順に読み、
│                  │  PUT / DEL レコードを適用
│                  │  (index を更新していく)
└──────┬───────────┘
       │
       ▼
┌──────────────────┐
│ Step 3:           │  インデックスが完全に再構築された状態で
│ サービス開始       │  stdio 受付を開始
└──────────────────┘

6. Snapshot 処理(rebuild_index の一部としても動作)

現在有効なデータ (deleted=false) を列挙
    │
    ▼
snapshot.tmp にシリアライズして書き出し
    │
    ▼
fsync(snapshot.tmp)
    │
    ▼
rename(snapshot.tmp → snapshot.bin)
    │  ← アトミック操作。クラッシュしても古い snapshot.bin が残る
    ▼
完了

役割: 起動時のログ再生量を減らし、起動時間を短縮する。
7. Compaction 処理

トリガー: ログファイルサイズが閾値を超えた または rebuild_index 呼出
    │
    ▼
現在有効なデータ (deleted=false) のみを列挙
    │
    ▼
new_active.log に有効レコードのみを書き出し
    │
    ▼
fsync(new_active.log)
    │
    ▼
rename(new_active.log → active.log)
    │  ← アトミック操作
    ▼
古いログファイルを削除
    │
    ▼
新しい snapshot.bin も生成 (compaction 後の状態を保存)
    │
    ▼
In-Memory Index の file_id / offset を更新

役割: ログ肥大化を防ぎ、ディスク使用量を削減する。
8. メモリ階層とデータライフサイクル

Message Object の metadata.memory_tier を用いて、LLM会話の寿命を管理します。

┌─────────────┬──────────────────────────┬──────────────────┐
│ 階層         │ 内容                      │ 保存場所           │
├─────────────┼──────────────────────────┼──────────────────┤
│ short (短期) │ 直近の会話メッセージ        │ メモリ + active.log│
│             │                          │ (即座に参照可能)    │
├─────────────┼──────────────────────────┼──────────────────┤
│ mid (中期)  │ セッションの要約・抽象化     │ active.log +      │
│             │                          │ snapshot          │
├─────────────┼──────────────────────────┼──────────────────┤
│ long (長期) │ 重要なユーザー設定・         │ snapshot 優先で   │
│             │ 継続的記憶 (key-value)      │ 永続化            │
├─────────────┼──────────────────────────┼──────────────────┤
│ discard     │ 一時的な雑談・重複情報・     │ compaction 時に   │
│ (破棄対象)   │ 古い全文ログ               │ 削除対象          │
└─────────────┴──────────────────────────┴──────────────────┘

ライフサイクル:

write_message (memory_tier=short)
    │
    │  セッション終了・要約トリガー
    ▼
要約生成 → write_message (memory_tier=mid)
    │  元の short メッセージを delete_message で論理削除
    ▼
compaction 時に short の deleted レコードが物理削除される
    │
    │  長期的に重要と判断されたもの
    ▼
write_message (memory_tier=long)
    │  snapshot 優先で永続化
    ▼
discard レコードは compaction 時に消える

9. MCP Tool とストレージ層の対応表(最終版)
Tool 	L2処理 	L3処理 	関連コンポーネント
write_message 	Index更新 + Queue追加 	flush時に active.log へ追記 	Write Queue, In-Memory Index
read_messages 	session_id で Index 検索 	pread() で該当レコード読み出し 	In-Memory Index, active.log
search_messages 	キーワードハッシュで Index 検索 	pread() で該当レコード読み出し 	In-Memory Index, active.log
delete_message 	Index の type を DEL に更新 	DEL レコードを active.log へ追記 	Write Queue, In-Memory Index
rebuild_index 	全有効データを再列挙 	snapshot 作成 + compaction 実行 	Snapshot, Compaction Worker
get_system_health 	各種カウンタ収集 	ログファイルサイズ・整合性チェック 	全コンポーネント