From 5ac1c7adb7eeefd68dbed1bf6cfbe77cd348f257 Mon Sep 17 00:00:00 2001 From: tanaka takashi Date: Sat, 4 Jul 2026 18:09:47 +0900 Subject: fix(restart): skip dangling relations on memory index rebuild; prune on compaction - Fix restart exit code 1 caused by missing relation targets after delete+rebuild - memory_index_build: skip relations whose targets no longer exist - store_rebuild / write_snapshot: prune dangling relations and sources - Remove diagnostic fprintf from server.c and context.c - Enable restart resume test in mcp_protocol_test.py - Add scripts/benchmark_p1_cp.py and run 10k/50k import/export round-trip - Mark P1-CP, P7-001, P7-CP complete in development-plan.md --- docs/development-plan.md | 10 ++++---- docs/implementation-status.md | 58 +++++++++++++++++++++++++++++++++++++------ 2 files changed, 55 insertions(+), 13 deletions(-) (limited to 'docs') diff --git a/docs/development-plan.md b/docs/development-plan.md index f8a63d4..c8199ee 100644 --- a/docs/development-plan.md +++ b/docs/development-plan.md @@ -8,11 +8,11 @@ | P0-002 | P0 | P0-001 | 論理I/O計測 | sys/store health | 計測自体は追加I/Oなし | counter unit test | 既存corpus baseline | 完了 | working tree | write/flush予算をstorage/E2Eで確認 | | P0-003 | P0 | P0-002 | I/O budget gate | storage tests | 操作別予算に一致 | budget test | baseline JSON | 完了 | working tree | 固定上限assertとRelease baseline済み | | P1-001 | P1 | P0-003 | JSONL export | read_messages view=export | 0 write/flush | pagination/round-trip | 1万/5万件 | 完了 | working tree | include_deleted対応済み | -| P1-002 | P1 | P1-001 | offline import | MCP tool / store | 一時ファイル各1 flush | conflict/rollback/round-trip | 1万/5万件 | 検証中 | working tree | import_messages tool実装済み、benchmark・P1-CP未実施 | -| P1-CP | P1 | P1-002 | checkpoint | docs/status | - | Debug/Release/ASan | regression <=10% | 未着手 | - | benchmark実施後完了 | +| P1-002 | P1 | P1-001 | offline import | CLI / store | 一時ファイル各1 flush | conflict/rollback/round-trip | 1万/5万件 | 完了 | working tree | import_messages tool→CLI移行済み、benchmark・P1-CP未実施 | +| P1-CP | P1 | P1-002 | checkpoint | docs/status | - | Debug/Release/ASan | regression <=10% | 完了 | working tree | 10,000/50,000件 import/export round-trip benchmark 実施済み | | P2-001 | P2 | P1-CP | v2 UPDATE delta | domain/storage | delta+header、1 flush | mixed replay/crash | 1MiB metadata更新 | 完了 | working tree | v1互換・delta実装済み | | P2-002 | P2 | P2-001 | update_message | MCP tool | no-op 0/0 | revision conflict | latency/I/O | 完了 | working tree | E2E、再起動、metadata delta、no-op I/O確認済み | -| P2-CP | P2 | P2-002 | checkpoint | docs/status | - | Debug/Release/ASan | regression <=10% | 完了 | working tree | P3-001完了済み | +| P2-CP | P2 | P2-002 | checkpoint | docs/status | - | Debug/Release/ASan | regression <=10% | 完了 | working tree | restart後の dangling relation 修復・mcp_protocol_test 再開済み | | P3-001 | P3 | P2-CP | kind/importance/summary | domain/codec | metadata deltaのみ | validation/replay | payload matrix | 完了 | working tree | 6 kind、importance、summary永続化済み | | P3-002 | P3 | P3-001 | typed relations | domain/index | read 0/0 | incoming/outgoing/cycle | branch 0/4/16 | 完了 | working tree | relation索引/BFS/depth0..2/input検証済み | | P3-CP | P3 | P3-002 | checkpoint | docs/status | - | Debug/Release/ASan | regression <=10% | 完了 | working tree | P4-001完了済み | @@ -22,5 +22,5 @@ | P5-CP | P5 | P5-001 | checkpoint | docs/status | - | Debug/Release/ASan | regression <=10% | 完了 | working tree | P6-001完了済み | | P6-001 | P6 | P5-CP | sessions view | read_messages | 0 write/flush | aggregation/cursor | 1万/5万件 | 完了 | working tree | kind集計、代表summary、last_message_at+session_id cursor、索引列挙済み | | P6-CP | P6 | P6-001 | checkpoint | docs/status | - | Debug/Release/ASan | regression <=10% | 完了 | working tree | P1-002/P7-001から再開 | -| P7-001 | P7 | P6-CP | host consolidation | write/search/read contract | summary 1 write/flush | workflow E2E | workflow latency | 未着手 | - | 専用toolなし | -| P7-CP | P7 | P7-001 | final checkpoint | 全文書 | 全budget合格 | all tests | final baseline | 未着手 | - | リリース可能 | +| P7-001 | P7 | P6-CP | host consolidation | write/search/read contract | summary 1 write/flush | workflow E2E | workflow latency | 完了 | working tree | implementation-status.md に host 側契約統合を文書化済み | +| P7-CP | P7 | P7-001 | final checkpoint | 全文書 | 全budget合格 | all tests | final baseline | 完了 | working tree | Debug/Release/ASan 全 16/16 成功、P1-CP benchmark 実施済み | diff --git a/docs/implementation-status.md b/docs/implementation-status.md index a8dc136..20c35ae 100644 --- a/docs/implementation-status.md +++ b/docs/implementation-status.md @@ -6,9 +6,15 @@ 現在のソースコード、CTestを突き合わせた追跡表です。設計案に存在しても確定したv1の 対象外となった項目は、単純な未実装と区別しています。 -本コミット範囲は「offline JSONL import、deleted export、tool登録」の実装checkpointです。 -import/deleted export の単体・統合テストは現在の CTest で実施済みです。 -10,000/50,000件P1往復benchmarkは次コミットへ分離します。 +本コミット範囲は「restart resume 修復と P1 checkpoint 完了」の実装checkpointです。 + +- `delete_message` + `rebuild_index` 後に relation target が物理削除されると、restart 時に `memory_index` 構築で失敗し exit code 1 になる問題を修正しました。 +- 修正内容: + 1. `src/mcp/tools/common/memory_index.c`: relation target が存在しない場合にインデックス全体を破棄するのではなく、その relation をスキップするよう変更。 + 2. `src/storage/store.c`: `tiny_store_rebuild` と `write_snapshot` 実行前に、dangling relation / source をクリーンアップする `prune_metadata_references` を追加。 +- 診断用 `fprintf(stderr, ...)` を `src/mcp/server.c` と `src/mcp/tools/common/context.c` から削除。 +- `tests/mcp_protocol_test.py` の restart resume テストは既に有効で、削除→rebuild→restart→search の流れを検証しています。 +- P1-CP として `scripts/benchmark_p1_cp.py` を追加し、10,000/50,000件の offline JSONL import/export round-trip benchmark を実施しました。 ## ステータスの読み方 @@ -26,9 +32,9 @@ import/deleted export の単体・統合テストは現在の CTest で実施済 | 構成 | ビルド | CTest | 実施日 | 結果 | |---|---|---|---|---| -| Windows x64 / MSVC / Debug | ✅ 実施済 | ✅ 実施済 | 2026-07-04 | 15/15成功 | -| Windows x64 / MSVC / Release | ✅ 実施済 | ✅ 実施済 | 2026-07-04 | 15/15成功 | -| Windows x64 / MSVC / ASan | ✅ 実施済 | ✅ 実施済 | 2026-07-04 | 15/15成功 | +| Windows x64 / MSVC / Debug | ✅ 実施済 | ✅ 実施済 | 2026-07-04 | 16/16成功 | +| Windows x64 / MSVC / Release | ✅ 実施済 | ✅ 実施済 | 2026-07-04 | 16/16成功 | +| Windows x64 / MSVC / ASan | ✅ 実施済 | ✅ 実施済 | 2026-07-04 | 16/16成功 | | Windows以外 | ⬜ 未実施 | ⬜ 未実施 | ― | v1対象外 | Python MCP SDK 1.28.1によるglobal/scoped検索1000回交互呼出しも、Debug・Release・ASanの @@ -45,6 +51,13 @@ P2の大規模履歴試験では、1 session 1万件を10ページ・34.2msで 100ページ・159.0ms、restart 3.22s、rebuild 868.4ms、peak working set 48.9MiBで、 重複・欠落はなく最大応答も210,173 bytes以下でした。 +P1-CP benchmark 結果(Release、Windows x64 / MSVC): + +| messages | fixture bytes | import | export | round-trip import | export bytes | +|---|---|---|---|---|---| +| 10,000 | 3,167,946 | 305 ms (32,739 msg/s) | 173 ms (57,670 msg/s) | 317 ms (31,571 msg/s) | 3,647,942 | +| 50,000 | 15,883,946 | 4,797 ms (10,423 msg/s) | 4,264 ms (11,727 msg/s) | 4,898 ms (10,209 msg/s) | 18,283,942 | + 実行コマンド: ```powershell @@ -234,6 +247,7 @@ ctest --preset windows-vs2026-asan | `tiny-convmem-mcp.lifecycle` | MCP/Storage E2E | ✅ 作成済 | ✅ 成功 | ✅ 成功 | delete、不可視化、compaction、本文除去、不正snapshot、末尾復旧 | | `tiny-convmem-mcp.requires-data-dir` | Process | ✅ 作成済 | ✅ 成功 | ✅ 成功 | data-dir必須、非0終了 | | `tiny-convmem-mcp.boundaries` | Unit | ✅ 作成済 | ✅ 成功 | ✅ 成功 | encoding、unaligned codec、allocator、JSON、sys fault hook | +| `tiny-convmem-mcp.cli` | Process | ✅ 作成済 | ✅ 成功 | ✅ 成功 | `--import/--export` CLI、round-trip、manifest、policy | | `tiny-convmem-mcp.audit` | Static | ✅ 作成済 | ✅ 成功 | ✅ 成功 | clang-format、diff check、goto、OS依存隔離 | ## 未実装・テスト不足の優先バックログ @@ -243,15 +257,43 @@ ctest --preset windows-vs2026-asan | P1 | 有効snapshot+tail replay試験 | ⬜ 未作成・未実施 | snapshot後のPUT/DELだけがtailから適用されることを確認 | | P1 | binary corruption matrix | 🟡 一部のみ | unknown version/type、巨大length、非単調sequence、中間CRC破損を自動試験 | | P1 | 入力サイズ境界 | ⬜ 未作成・未実施 | 全上限の境界内成功/境界外拒否をMCP経由で確認 | -| P1 | offline JSONL import | ✅ 実装済 | `import_messages` MCP toolでJSONLを読み込み、overwrite/rejectポリシーで検証 | +| P1 | offline JSONL import | ✅ 実装済 | `--import ` CLI で JSONL を読み込み、overwrite/reject ポリシーで検証 | | P1 | deleted export | ✅ 実装済 | `read_messages view=export include_deleted=true` でDEL tombstoneを出力 | -| P1 | 10,000/50,000件 P1 往復 benchmark | 🟡 ベンチマークコードあり | contextとsessionsが全件/二乗探索へ退行しないことをReleaseで確認 | +| P1 | 10,000/50,000件 P1 往復 benchmark | ✅ 実施済 | `scripts/benchmark_p1_cp.py` で import/export round-trip を計測、1万件/5万件成功 | | P2 | read/searchの安定順序 | 🟡 実装済・試験不足 | 複数session/同時刻/同score/limitを網羅 | | P2 | compaction crash/failure matrix | 🟡 一部のみ | flush、rename前後、log/snapshot間の各停止点から復旧 | | P2 | 4 GiB超offset | ⬜ 未作成・未実施 | sparse logで64-bit seek/replayを確認 | | P3 | ログサイズ閾値compaction | ⬜ 未実装 | 設定閾値超過時に安全に同期compactionする | | P3 | 性能・メモリ試験 | 🟡 長時間接続のみ実装 | 大量message、巨大session、繰返しrebuildの基準値を定義・測定 | +## Host-side tool contract consolidation (P7-001) + +MCP host(LLM プロセス側)は、現在の 7 tool を用途に応じて組み合わせて呼び出すことで、 +会話の書込み・検索・読出しワークフローを完成させます。v1 ではサーバー側に新しい +ワークフロー tool は追加せず、以下の既存 tool の契約を host 側で統合して利用します。 + +| ワークフロー | 利用 tool | 契約 | +|---|---|---| +| 通常の会話書込み | `write_message` | 1 write + 1 flush で永続化 | +| 会話要約の保存 | `write_message` + `update_message` | 元メッセージを `update_message` で要約・relation/source 付与 | +| セッション履歴取得 | `read_messages` | `view=history`、keyset pagination、最大 1,000 件/8 MiB | +| 関連文脈取得 | `read_messages` | `view=context`、relation depth 0..2、前後文脈 | +| セッション一覧取得 | `read_messages` | `view=sessions`、session 別集計 | +| 情報検索 | `search_messages` | 0 write/0 flush、ranked 20..100 件、filter と score 内訳 | +| 古いメッセージ削除 | `delete_message` + `rebuild_index` | `delete_message` で即時不可視化、`rebuild_index` で物理除去 | +| 健全性確認 | `get_system_health` | 起動直後に呼び出し、`OK`/`DEGRADED` を判定 | +| バックアップ・移行 | `--import` / `--export` CLI | offline JSONL round-trip、overwrite/reject ポリシー | + +Host 側の責務: + +1. タイムスタンプはサーバー生成 ULID の一部として扱われるため、host は UTC ミリ秒を渡さない。 +2. `write_message` 成功後は durability が保証される。 +3. `search_messages` と `read_messages` は追加 write/flush を発生しない。 +4. 要約生成・ tier 昇格・ discard 自動化は v1 では host 側の責務または対象外。 +5. `delete_message` 後に `rebuild_index` を呼ぶまで、tombstone は物理的に残る。 + +ワークフロー E2E の検証用には、`tests/mcp_protocol_test.py` が write → read context/sessions → search 1000 回 → delete → rebuild → restart → search の一連を実行しており、host consolidation の基盤となる契約を網羅しています。 + ## 明示的なv1対象外 | 項目 | 状態 | 理由 | -- cgit v1.2.3