yoi/tickets/memory-file-format.review.md

7.8 KiB
Raw Blame History

Review: メモリ機構: ファイル形式 + Linter 土台

前提・要件の確認

完了条件マッピング

# 条件 結果 根拠
1 crates/memory/ 新設、workspace 登録 OK Cargo.toml:13, crates/memory/Cargo.toml, crates/memory/src/lib.rs:9-15
2 memory tool 3 種read / write / editが登録できる OK crates/pod/src/controller.rs:243-252
3 違反 content で複数違反集約の InvalidArgument、fs 不変 OK crates/memory/src/tool/write.rs:185-202, :237-249linter::format_report で全 error を 1 メッセージに集約
4 正常 content は通常書き込み OK tool/write.rs:147-163
5 memory/workflow/ 書き込み拒否 OK linter/mod.rs:101-105tool/write.rs:165-181, tool/edit.rs:276-298
6 同 slug 新規作成 error OK linter/mod.rs:120-127, tool/write.rs:204-222
7 replaced_by / requires の参照切れと循環が error 部分 replaced_by 不在: OK / replaced_by 循環: アルゴリズム実装済みだが実循環ケースの end-to-end テスト無し / requires 整合: 未実装schema/workflow.rs で型パースのみ)
8 Pod 有効化で generic tool Scope deny OK pod.rs:1516-1527 (build_scope_with_memory)、scope::deny_write_rules
9 既存ビルド・テスト壊さない OK cargo build --workspace / cargo test --workspace 全 pass、memory 単体 44 テスト pass

Linter ルール(要件節)と実装の照合

静的 error:

  • frontmatter 必須欠落・型違反: OK (linter/frontmatter.rs::map_serde_error、ただし parse_invalid_status\open`` リテラル含有でラフに status 同定する点はやや fragile — 別フィールドが今後 enum を持つ場合は誤分類リスク)
  • workflow 書き込み禁止: OK
  • 同 slug 新規禁止: OK
  • replaced_by 実在: OK
  • replaced_by 循環: 実装あり / テスト不足
  • Decisions status enum: OK
  • slug 文法: OK (slug::is_valid_slug + 全網羅 deserialize 経路)
  • model_invokation: true の description 1024 上限: OK
  • 種別ごとの char 硬上限 (summary 20000 / 他 8000): OK

膨張抑制 Warn:

  • 大 record × 単一 sources warn: OK
  • sources 配列長 warn: OK
  • 類似 slug 乱立 (Levenshtein 距離 2 / 3 件以上) warn: 未実装LintWarning::SimilarSlugs バリアントは定義済みだが、emit 経路無し。existing.slugs(kind) は揃っており実装は容易)

アーキテクチャ・スコープ

良い点

  • memory 関連は crates/memory/ に明確に閉じ込められている。tools/ 側に侵入なし、pod 側は MemoryConfig 取得 + build_scope_with_memory + tool 登録 3 行のみで責務が薄い
  • crate 名は memoryinsomnia- プレフィックス無し(命名ルール準拠)
  • 依存追加は cargo add 由来とみられる版指定で workspace に整合(crates/memory/Cargo.toml
  • schema/, linter/, tool/ を feature module で分割しており、巨大 lib.rs を回避
  • LLM への違反伝達は ToolError::InvalidArgument のみで完結。Interceptor 拡張・retry message 注入・違反カウンタを持たないという設計方針通り
  • 公開 API は lib.rs 12 行で抑制的、leaky でない
  • _staging/ は意図通り linter 透過 (workspace::classifyOk(None))

懸念

  • plan 残存矛盾: docs/plan/memory.md:196 に「Phase 2 と同じ CRUD tool + Linter Hook を使う」が残っている。「Linter Hook」は本チケットで否定された旧設計の語彙。GC 節の更新漏れ4 箇所更新と説明されたが GC 節は対象外だった可能性)
  • deny target = <workspace_root>/memory: MemoryConfig::workspace_rootNone の時 pwd を採用するが、pwd ≠ workspace root の Pod を spawn したケースで deny 対象パスがズレ、generic write が実際の memory/ を保護しない可能性。ticket 要件は文字通りには満たしているが、「workspace_root 既定値が pwd」前提が manifest 側で文書化されていない。PodManifest 化のドクコメントに「workspace_root 未指定 ⇒ Pod 構築時 pwd」と書く程度は欲しい

指摘事項

Blocking

なし。完了条件 7 は部分的だが、requires の検証は memory tool 経由で書き込む経路がticket の禁止により存在しないため、実害が無い。CLI / pre-commit が別チケットに切り出されていることと整合する

Non-blocking / Follow-up

  • 類似 slug 乱立 warn 未実装crates/memory/src/error.rs:101 SimilarSlugs バリアントは定義済みだが emit されない。ticket 要件節「膨張抑制 Warn」に明記されているので、本ライフサイクル内に追加するか、後続 ticket に明示移管したい
  • requires 参照整合チェック未実装lint_workflow_frontmatter (linter/mod.rs:235) は型パースだけで、requires: Vec<Slug> の各 slug が実在 Workflow か検査しない。memory tool では到達しないが、ticket 完了条件に文言が残っている。CLI ticket に明示的に移すか、本チケットで lint_workflow_frontmatter の引数に &ExistingRecords を渡す形で実装するのが筋
  • replaced_by 循環の end-to-end テスト追加references.rs::tests::empty_chain_terminates は smoke test に近い。A.replaced_by=B, B.replaced_by=Aexisting に置いた状態で 2 ノード閉路を実検出するテストを足すと完了条件 7 のカバレッジが揃う
  • docs/plan/memory.md:196 — 「Linter Hook」を「Lintermemory tool 内 pre-write 検証」相当に書き換え。GC 節は本チケットの直接対象外でも、用語整合は取りたい
  • MemoryConfig.workspace_root 既定値の文書化crates/manifest/src/lib.rs:46-53 のドクコメントに「None ⇒ Pod の pwd 採用」「pwd ≠ workspace root の Pod では明示指定が必要」を追記
  • lint_workflow_frontmatterlib.rs 公開 — CLI 経路の入口になる関数なので memory::Linter と並んで pub use linter::lint_workflow_frontmatter; しておくと後続 CLI ticket が触れやすい

Nits

  • linter/frontmatter.rs::parse_invalid_status\open` 文字列マッチで status enum を識別するため、将来別の enum (status-like) が増えた時に誤分類するリスク。コメント注記はあるが、field: "status"` ハードコード分岐に何らかのテストを足したい
  • tool/edit.rsformat_report / warning_tailtool/write.rs の同名関数とロジックがほぼ重複。tool/mod.rs に小さなヘルパとして括り出すと DRY に
  • SourceRef.range: [u64; 2] は frontmatter での扱いが配列だが、構造体名コメントが「inclusive range」とのみ。ドクコメントに「[start_entry_index, end_entry_index] 両端含む」を簡潔に書くと session-store との対応が明示される
  • Slug::PartialOrd / Ord は派生済みだが、HashMap<Slug, _> で十分なので BTreeMap 用途が現状無い。問題ないが意図メモがあると親切

判断

Approve with follow-up — 完了条件はほぼ全て充足。アーキテクチャ的に memory 専用クレートへ綺麗に閉じ込められ、tools / pod への漏出は最小5 行程度。LLM 違反伝達も ToolError::InvalidArgument 一本で完結し、ticket 設計方針に忠実。残課題(類似 slug warn / requires 検証 / 循環 e2e テスト / plan 残存表現 / workspace_root ドキュメント)はいずれも非 blocking で、別 PR / 追跡 ticket への計上で十分。ビルド・テストともに workspace 全 pass。