From 8c12e799da8364f3a1b0b27d104a048099f24fb5 Mon Sep 17 00:00:00 2001 From: Hare Date: Fri, 8 May 2026 00:59:08 +0900 Subject: [PATCH] =?UTF-8?q?update:=20Workflow=E3=83=87=E3=82=A3=E3=83=AC?= =?UTF-8?q?=E3=82=AF=E3=83=88=E3=83=AA=E4=BF=AE=E6=AD=A3=E3=81=AE=E3=83=95?= =?UTF-8?q?=E3=82=A9=E3=83=AD=E3=83=BC=E3=82=A2=E3=83=83=E3=83=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- crates/memory/src/tool/query.rs | 4 +-- tickets/internal-worker-workflow.md | 6 ++-- tickets/workflow-directory-layout.md | 6 ++++ tickets/workflow-directory-layout.review.md | 38 +++++++++++++++++++++ 4 files changed, 49 insertions(+), 5 deletions(-) create mode 100644 tickets/workflow-directory-layout.review.md diff --git a/crates/memory/src/tool/query.rs b/crates/memory/src/tool/query.rs index d412b988..35772e2d 100644 --- a/crates/memory/src/tool/query.rs +++ b/crates/memory/src/tool/query.rs @@ -443,8 +443,8 @@ mod tests { let layout = WorkspaceLayout::new(dir.path().to_path_buf()); std::fs::create_dir_all(dir.path().join(".insomnia/memory/decisions")).unwrap(); std::fs::create_dir_all(dir.path().join(".insomnia/memory/requests")).unwrap(); - std::fs::create_dir_all(dir.path().join(".insomnia/memory/workflow")).unwrap(); std::fs::create_dir_all(dir.path().join(".insomnia/memory/_staging")).unwrap(); + std::fs::create_dir_all(dir.path().join(".insomnia/workflow")).unwrap(); std::fs::create_dir_all(dir.path().join(".insomnia/knowledge")).unwrap(); (dir, layout) } @@ -556,7 +556,7 @@ mod tests { #[tokio::test] async fn memory_query_excludes_workflow_and_staging() { let (dir, layout) = setup(); - let wf = dir.path().join(".insomnia/memory/workflow/wf.md"); + let wf = dir.path().join(".insomnia/workflow/wf.md"); std::fs::write(&wf, "needle in workflow\n").unwrap(); let stg = dir.path().join(".insomnia/memory/_staging/abc.json"); std::fs::write(&stg, "needle in staging\n").unwrap(); diff --git a/tickets/internal-worker-workflow.md b/tickets/internal-worker-workflow.md index e8feffde..a55d1645 100644 --- a/tickets/internal-worker-workflow.md +++ b/tickets/internal-worker-workflow.md @@ -8,7 +8,7 @@ INSOMNIA が内部で固定 prompt を持って disposable Worker / 専用 Pod - Phase 2 統合 + 整理(`tickets/memory-phase2-consolidation.md`、本チケット時点では実装中 / 直前) - Compact(`PromptCatalog::compact_system`) -これらは実装内 `&str` 定数や `PromptCatalog` の overlay で管理されており、prompt の調整や運用カスタマイズが「コード変更 + 再ビルド」を要する。一方、ユーザー向け `/` Workflow(`tickets/workflow.md`)は `/.insomnia/memory/workflow/.md` に住み、frontmatter + Markdown 本文 + `requires` Knowledge inject を持つ宣言形式で運用できる。 +これらは実装内 `&str` 定数や `PromptCatalog` の overlay で管理されており、prompt の調整や運用カスタマイズが「コード変更 + 再ビルド」を要する。一方、ユーザー向け `/` Workflow(`tickets/workflow.md`)は `/.insomnia/workflow/.md` に住み、frontmatter + Markdown 本文 + `requires` Knowledge inject を持つ宣言形式で運用できる。 両者を寄せ、内部 Worker / 内部 Pod の prompt + ツール surface + Knowledge 依存を **Workflow と同一仕様で記述** できる経路を用意する。これにより: @@ -22,7 +22,7 @@ INSOMNIA が内部で固定 prompt を持って disposable Worker / 専用 Pod `tickets/workflow.md` の Workflow 仕様は「ユーザーが `/` で submit する制約付き作業」だが、本チケットでは **内部トリガー(Pod 内部の状態遷移)から呼び出される Workflow** を一級扱いに広げる。 -- 同じファイル形式(`memory/workflow/.md`)、同じ frontmatter / Linter +- 同じファイル形式(`.insomnia/workflow/.md`)、同じ frontmatter / Linter - `user_invocable: false` で `/` 経路から見えなくする - `model_invokation` は通常 Pod 用の system prompt 注入仕様のまま(内部 Workflow は通常 OFF) - 内部 Workflow を識別するキー(例: `internal_role`)と、必要なツール surface を表明する手段を frontmatter に追加する。具体 schema は実装で詰める @@ -59,7 +59,7 @@ Pod 側の既存トリガー(Phase 1 post-run / Phase 2 staging 閾値 / Compa ## 完了条件 - 各内部 Worker / 内部 Pod(少なくとも Phase 1 / Phase 2 / Compact のうち、本チケット着手時点で実装済みのもの)が内部識別キー付き Workflow を解決して prompt とツール surface を組み立てる -- workspace で `memory/workflow/.md` を上書きすれば内部 Worker の prompt が変わる +- workspace で `.insomnia/workflow/.md` を上書きすれば内部 Worker の prompt が変わる - workspace に該当 Workflow が無い場合、bundled default が使われる - `user_invocable: false` の内部 Workflow は `/` 候補から除外され、ユーザーからは呼べない - 内部 Workflow も consolidation の自動書き込み禁止対象のまま(Linter で構造的担保、`workflow.md` と整合) diff --git a/tickets/workflow-directory-layout.md b/tickets/workflow-directory-layout.md index f060f1b2..881122fa 100644 --- a/tickets/workflow-directory-layout.md +++ b/tickets/workflow-directory-layout.md @@ -113,3 +113,9 @@ workspace に既存 Workflow がある場合、新配置へ移す。 - `crates/pod/src/workflow/mod.rs` - `tickets/auto-maintain-workflow.md` - `tickets/internal-worker-workflow.md` + +## Review + +- 状態: Approve +- レビュー詳細: [./workflow-directory-layout.review.md](./workflow-directory-layout.review.md) +- 日付: 2026-05-08 diff --git a/tickets/workflow-directory-layout.review.md b/tickets/workflow-directory-layout.review.md new file mode 100644 index 00000000..df21a382 --- /dev/null +++ b/tickets/workflow-directory-layout.review.md @@ -0,0 +1,38 @@ +# Review: Workflow の物理配置を `.insomnia/workflow` に分離する + +対象 commit: `04f1837 feat: Workflowの読み取り位置変更の実装` + +## 前提・要件の確認 + +- **canonical path 変更**: `crates/memory/src/workspace.rs:120-122` で `workflow_dir()` が `insomnia_dir().join("workflow")` を返すようになっており、`.insomnia/workflow/.md` が canonical。`crates/memory/src/workspace.rs:163` の `classify` も新配置を `RecordKind::Workflow` として返す。OK +- **旧配置は読まない / linter / scope deny も新配置のみ**: `load_workflows` は `layout.workflow_dir()` のみを開く(`crates/memory/src/workflow.rs:184-205`)。`scan_existing` も同様(`crates/memory/src/linter/existing.rs:85-88`)。`deny_write_rules` は memory / knowledge / workflow の 3 ディレクトリ(`crates/memory/src/scope.rs:23-29`)。`workspace::workflow_under_memory_is_invalid_path` と `workflow::workflow_under_memory_is_ignored` で「旧配置は無視される」ことを test 化(`crates/memory/src/workspace.rs:280-286`、`crates/memory/src/workflow.rs:374-389`)。OK +- **linter / WorkflowRegistry / completion / resident workflow**: `lint_workflow` は `existing::scan_existing` 経由で新配置の `requires` 検査を維持。`Linter::lint` が `RecordKind::Workflow` を即座に `WorkflowWriteForbidden` で弾く(`crates/memory/src/linter/mod.rs:103-106`)。`WorkflowRegistry` は新配置の path のみ保持(`crates/memory/src/workflow.rs:246-256`)。pod 側の resolver / resident 広告も `layout.workflow_dir()` 経由で同様に流用される(`crates/pod/src/workflow/mod.rs:150,174,187`、`crates/pod/src/prompt/system.rs:157`)。OK +- **`.insomnia/.gitignore`**: `/memory/_staging/` `/memory/summary.md` `/memory/decisions/` `/memory/requests/` のみを ignore に変更(`.insomnia/.gitignore`)。`git ls-files .insomnia/` で `manifest.toml` / `workflow/auto-maintain.md` / `workflow/worktree-workflow.md` が tracked、`git check-ignore` で generated state のみが ignore されているのを確認した。OK +- **既存 workflow ファイルの移行**: `.insomnia/workflow/auto-maintain.md` と `.insomnia/workflow/worktree-workflow.md` が新配置に存在し、旧 `.insomnia/memory/workflow/` ディレクトリは現存しない。OK +- **ドキュメント / チケット本文の更新**: `docs/plan/workflow.md`、`docs/plan/memory.md`、`crates/memory/src/{schema/workflow.rs,skill.rs,tool/query.rs}` の doc コメント、`crates/pod/src/{pod.rs,prompt/system.rs}` のコメントが新配置に更新済み。チケット本文も「互換読み取り」要件削除と完了条件の更新が反映されている。OK + +`cargo test --workspace` も全パス(memory crate 122 件含む)。 + +## アーキテクチャ・スコープ + +- **Workflow の memory subsystem からの分離**: 物理配置のみ memory tree から外し、loader / linter / scope は引き続き memory crate 内で管理する形。これは「Workflow は session-derived state ではないが、project-managed なリソースとして memory 周辺の一貫した検査機構(frontmatter validator、`requires` reference check、scope deny)を共用する」という現状設計とずれていない。新規 crate 切り出しなどの過剰な構造変更を避けており妥当。 +- **scope deny**: `deny_write_rules` に `workflow_dir()` を追加するのは memory tool の generic CRUD パスを Workflow path に到達させない目的。doc コメント(`crates/memory/src/scope.rs:14-18`)で「Workflow files are human-edited on the host side」と明示しており、想定ポリシーと整合。 +- **classify の対称性**: `classify` の if 分岐順序は knowledge → workflow → memory(`crates/memory/src/workspace.rs:157-167`)の順で、`memory_dir()` 配下の旧 `memory/workflow/` を `RecordKind::Workflow` に分岐させる経路を完全に削っている。`workflow_under_memory_is_invalid_path` test がこの挙動を保護している。 +- **互換コードの除去**: 旧 fallback 読み取りの実装が一切残っていないことを確認した。merge 関数や priority 比較などの互換複雑度を抱え込まず、要件の更新(後方互換不要)に沿って最小実装。コードベースを歪めていない。 +- **不必要な実装は混入していない**。差分は path 定数 1 行の移動、`classify` 分岐 1 つ追加、`deny_write_rules` 1 行追加、loader / linter から `WORKFLOW_DIR` segment の削除、テスト 3 件追加に留まる。 + +## 指摘事項 + +### Non-blocking / Follow-up + +- **`crates/memory/src/tool/query.rs` の test fixture が legacy path を使っている** — `setup` で `.insomnia/memory/workflow` を作成(line 446)し、`memory_query_excludes_workflow_and_staging` でも legacy path にファイルを書く(line 559)。`MemoryQuery` は `decisions_dir` / `requests_dir` / `summary` のみを scan するので、test の主張(query から workflow が見えない)自体は今でも成立しているが、canonical path が `.insomnia/workflow/` に移った今では「workflow を memory tree に置いて除外を確認する」という構図が古い。`.insomnia/workflow/wf.md` に書き換えるか、test の意図を「memory tree 配下の異物を query が拾わない」と捉え直してコメントを添えると正確。 +- **`tickets/internal-worker-workflow.md` の path 表記が古い** — 別ティケットだが、line 11 / 25 / 62 に `/.insomnia/memory/workflow/.md` `memory/workflow/.md` が残っている。本チケットの完了条件には含まれないが、次にそのチケットへ着手する人が誤った前提で実装を組まないよう、近い将来の更新が望ましい。 +- **TODO.md の該当行** — `TODO.md:4` に本チケットへのリンクが残っている。完了 commit でユーザーが削除する想定(CLAUDE.md のライフサイクル d)なので report しておくのみ。 + +### Nits + +- `.insomnia/.gitignore` の末尾に `# Project-authored workflows and knowledge are intentionally tracked.` というコメントが入っているが、`knowledge/` は対象 ticket の範囲外(既に追跡されていた)。意図は分かるが、本ファイルがこの ticket の範囲では「workflow が tracked になる」ことを表明しているとみなせるので問題なし。 + +## 判断 + +**Approve(完了可)** — 要件はすべて満たされており、後方互換不要に切り替えた更新方針に沿って最小・整合性のある実装になっている。Non-blocking で挙げた `tool/query.rs` test の legacy path 残置は別途整理可能。