refactor: rename pod crate to worker

This commit is contained in:
2026-06-26 00:05:57 +09:00
parent 4c677640f4
commit 6c59fe927b
194 changed files with 6637 additions and 6146 deletions
+1 -1
View File
@@ -31,7 +31,7 @@ pub fn build_consolidate_input(
"consolidation input. Run the integration step first \
(fold the staging activity logs into memory and knowledge), then the \
tidy step (clean up existing records). Use the memory tools for \
every write — direct file writes are denied by the pod scope.\n\n",
every write — direct file writes are denied by the worker scope.\n\n",
);
out.push_str("## Staging entries (consumed by this run)\n\n");
+18 -17
View File
@@ -2,7 +2,7 @@
//!
//! `docs/plan/memory.md` §並走防止 に従い:
//!
//! - ファイルが存在し、記録された Pod が動作している間、その Pod が排他占有
//! - ファイルが存在し、記録された Worker が動作している間、その Worker が排他占有
//! - クラッシュで残った stale lock は、所有者 PID が死んでいれば次回 spawn
//! 時に上書き取得できる
//! - cleanup は consumed ID の staging エントリのみ削除し、実行中に extract
@@ -22,12 +22,12 @@ use crate::workspace::WorkspaceLayout;
const LOCK_FILE: &str = ".consolidation.lock";
/// 占有ファイルの中身。`pid` で stale 判定し、`pod_name` / `started_at` /
/// 占有ファイルの中身。`pid` で stale 判定し、`worker_name` / `started_at` /
/// `consumed_ids` は診断とクラッシュ復旧時の参照に使う。
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LockRecord {
pub pid: u32,
pub pod_name: String,
pub worker_name: String,
pub started_at: DateTime<Utc>,
/// この consolidation run が起動時スナップショットで確定した consumed staging
/// entry の UUIDv7 列。完了時はこの列のみ削除し、追加分は残す。
@@ -38,8 +38,8 @@ pub struct LockRecord {
#[derive(Debug, thiserror::Error)]
pub enum LockError {
/// 占有ファイルが既にあり、所有者 PID が生きているのでスキップ。
#[error("consolidation lock held by live pid {pid} (pod {pod_name:?})")]
InUse { pid: u32, pod_name: String },
#[error("consolidation lock held by live pid {pid} (worker {worker_name:?})")]
InUse { pid: u32, worker_name: String },
#[error("io error at {}: {source}", .path.display())]
Io {
path: PathBuf,
@@ -85,7 +85,7 @@ impl StagingLock {
pub fn acquire(
layout: &WorkspaceLayout,
pid: u32,
pod_name: impl Into<String>,
worker_name: impl Into<String>,
consumed_ids: Vec<Uuid>,
) -> Result<Self, LockError> {
let staging_dir = layout.staging_dir();
@@ -99,12 +99,12 @@ impl StagingLock {
if pid_is_alive(existing.pid) {
return Err(LockError::InUse {
pid: existing.pid,
pod_name: existing.pod_name,
worker_name: existing.worker_name,
});
}
tracing::warn!(
stale_pid = existing.pid,
stale_pod = %existing.pod_name,
stale_pod = %existing.worker_name,
"consolidation stale lock detected, taking over"
);
} else {
@@ -114,7 +114,7 @@ impl StagingLock {
let record = LockRecord {
pid,
pod_name: pod_name.into(),
worker_name: worker_name.into(),
started_at: Utc::now(),
consumed_ids,
};
@@ -213,11 +213,11 @@ mod tests {
#[test]
fn acquire_writes_lock_file() {
let (_dir, layout) = make_layout();
let lock = StagingLock::acquire(&layout, std::process::id(), "pod", Vec::new()).unwrap();
let lock = StagingLock::acquire(&layout, std::process::id(), "worker", Vec::new()).unwrap();
let path = layout.staging_dir().join(LOCK_FILE);
assert!(path.exists());
assert_eq!(lock.record().pid, std::process::id());
assert_eq!(lock.record().pod_name, "pod");
assert_eq!(lock.record().worker_name, "worker");
}
#[test]
@@ -225,8 +225,8 @@ mod tests {
let (_dir, layout) = make_layout();
// Use this test process's pid — it's definitely alive.
let _first =
StagingLock::acquire(&layout, std::process::id(), "pod-a", Vec::new()).unwrap();
let err = StagingLock::acquire(&layout, std::process::id(), "pod-b", Vec::new())
StagingLock::acquire(&layout, std::process::id(), "worker-a", Vec::new()).unwrap();
let err = StagingLock::acquire(&layout, std::process::id(), "worker-b", Vec::new())
.expect_err("expected InUse");
assert!(matches!(err, LockError::InUse { .. }));
}
@@ -239,7 +239,7 @@ mod tests {
// dead on every platform we target.
let stale = LockRecord {
pid: u32::MAX,
pod_name: "ghost".into(),
worker_name: "ghost".into(),
started_at: Utc::now(),
consumed_ids: Vec::new(),
};
@@ -249,7 +249,7 @@ mod tests {
)
.unwrap();
let lock = StagingLock::acquire(&layout, std::process::id(), "pod", Vec::new())
let lock = StagingLock::acquire(&layout, std::process::id(), "worker", Vec::new())
.expect("stale lock must be overwritable");
assert_eq!(lock.record().pid, std::process::id());
}
@@ -276,7 +276,7 @@ mod tests {
)
.unwrap();
let lock = StagingLock::acquire(&layout, std::process::id(), "pod", vec![id_a]).unwrap();
let lock = StagingLock::acquire(&layout, std::process::id(), "worker", vec![id_a]).unwrap();
let lock_path = lock.path().to_path_buf();
lock.release_with_cleanup(&layout);
@@ -295,7 +295,8 @@ mod tests {
fn release_is_resilient_to_missing_consumed_entries() {
let (_dir, layout) = make_layout();
let phantom = uuid::Uuid::now_v7();
let lock = StagingLock::acquire(&layout, std::process::id(), "pod", vec![phantom]).unwrap();
let lock =
StagingLock::acquire(&layout, std::process::id(), "worker", vec![phantom]).unwrap();
let lock_path = lock.path().to_path_buf();
// No file at <staging>/<phantom>.json — release must not panic.
lock.release_with_cleanup(&layout);
+4 -4
View File
@@ -2,8 +2,8 @@
//!
//! extract が staging に残した活動ログを `memory/*` / `knowledge/*` に
//! 統合し、続けて既存 record を `outdated | superseded | unused | noisy`
//! の観点で整理する disposable Engine を、Pod 側が組み立てるための
//! ヘルパー群を提供する。Pod は次の手順で sub-Engine を構築する:
//! の観点で整理する disposable Engine を、Worker 側が組み立てるための
//! ヘルパー群を提供する。Worker は次の手順で sub-Engine を構築する:
//!
//! - [`build_consolidate_input`] を sub-Engine の最初の user 入力に
//! - memory 専用 Tool (read / write / edit) と Knowledge / memory 検索ツールを登録
@@ -11,8 +11,8 @@
//! - sub-Engine run 完了後、[`StagingLock::release_with_cleanup`] で
//! consumed ID 分の staging のみ削除し、占有ファイルを解放
//!
//! system prompt は Pod の `PromptCatalog`
//! (`PodPrompt::MemoryConsolidationSystem`) で管理される。Usage report は
//! system prompt は Worker の `PromptCatalog`
//! (`WorkerPrompt::MemoryConsolidationSystem`) で管理される。Usage report は
//! 判断材料として渡すだけで、ここでは Knowledge 化や protection の hard decision はしない
//! `docs/plan/memory.md` §Consolidation / 整理材料)。
+1 -1
View File
@@ -1,6 +1,6 @@
//! extract sub-Engine への入力テキスト組み立て。
//!
//! `crates/pod/src/pod.rs::build_summary_prompt` と同じ方針で
//! `crates/worker/src/worker.rs::build_summary_prompt` と同じ方針で
//! Item 列を flat な行に落とす(reasoning は省く、tool call は名前のみ、
//! tool result は summary のみ)。conversation 全体を Markdown の単一
//! セクションとして渡し、抽出指示は system prompt 側に寄せる。
+5 -5
View File
@@ -1,17 +1,17 @@
//! extract: 活動抽出。
//!
//! 通常 Pod の post-run hook で発火する disposable Engine と、その
//! 通常 Worker の post-run hook で発火する disposable Engine と、その
//! 出力を `<workspace>/.yoi/memory/_staging/<id>.json` に書き出す
//! ヘルパーを提供する。Pod 側はこのモジュールから:
//! ヘルパーを提供する。Worker 側はこのモジュールから:
//!
//! - [`build_extract_input`] を sub-Engine の最初の user 入力に
//! - [`write_extracted_tool`] を唯一のツールとして
//! - [`write_staging`] で受け取った JSON を staging に書き出し
//!
//! の順で組み立てる。system prompt は Pod の `PromptCatalog`
//! (`PodPrompt::MemoryExtractSystem`) で管理される。pointer 永続化
//! の順で組み立てる。system prompt は Worker の `PromptCatalog`
//! (`WorkerPrompt::MemoryExtractSystem`) で管理される。pointer 永続化
//! session-store の `LogEntry::Extension`、domain `"memory.extract"`)は
//! Pod 側が責務を持つ。
//! Worker 側が責務を持つ。
//!
//! 出力 JSON の wrap は [`write_staging`] が `source: { segment_id, range }`
//! を機械付与する形で担当し、LLM には source を推論させない。
+2 -2
View File
@@ -1,6 +1,6 @@
//! extract 抽出の出力 schema。
//!
//! LLM は [`ExtractedPayload`] そのもの(source 抜き)を返し、Pod
//! LLM は [`ExtractedPayload`] そのもの(source 抜き)を返し、Worker
//! ラッパーが [`StagingRecord`] に組み立てて staging へ書き出す。
//! source は機械付与する契約 (`docs/plan/memory.md` §Extract)。
@@ -78,7 +78,7 @@ pub struct RequestEntry {
/// staging に書き出される 1 ファイル分のレコード。
///
/// `source` は Pod 側ラッパーが segment_id と log entry range を
/// `source` は Worker 側ラッパーが segment_id と log entry range を
/// 機械付与する。LLM はこのフィールドを見ない / 推論しない。
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct StagingRecord {
+1 -1
View File
@@ -1,6 +1,6 @@
//! `LogEntry::Extension { domain: "memory.extract", payload }` の payload 形式と
//! restore 時の fold ヘルパー。memory crate がドメインを所有するので、
//! session-store / Pod は payload 構造を知らない。
//! session-store / Worker は payload 構造を知らない。
use serde::{Deserialize, Serialize};
+3 -3
View File
@@ -2,7 +2,7 @@
//!
//! sub-Engine からは extract worker が出した [`ExtractedPayload`] を
//! 受け取って `Mutex` 越しに [`ExtractWorkerContext`] に置くだけ。
//! Pod 側はランループ完了後に `take_payload()` で取り出して
//! Worker 側はランループ完了後に `take_payload()` で取り出して
//! [`super::staging::write_staging`] に渡す。
use std::sync::{Arc, Mutex};
@@ -22,7 +22,7 @@ the wrapper attaches provenance mechanically.";
pub struct ExtractWorkerContext {
payload: Mutex<Option<ExtractedPayload>>,
/// `write_extracted` が複数回呼ばれた回数(debug 用)。
/// 後勝ちで上書きするが、Pod 側で warn を出したい場合に参照する。
/// 後勝ちで上書きするが、Worker 側で warn を出したい場合に参照する。
call_count: Mutex<usize>,
}
@@ -31,7 +31,7 @@ impl ExtractWorkerContext {
Self::default()
}
/// sub-Engine 終了後に Pod が呼んで payload を取り出す。
/// sub-Engine 終了後に Worker が呼んで payload を取り出す。
/// 一度も `write_extracted` が呼ばれなければ `None`。
pub fn take_payload(&self) -> Option<ExtractedPayload> {
self.payload
+1 -1
View File
@@ -3,7 +3,7 @@
//! Self-contained: provides its own Tool implementations (read/write/edit)
//! that target `<workspace>/memory/` and `<workspace>/knowledge/` only,
//! with a pre-write Linter built in. Generic CRUD tools (in the `tools`
//! crate) must not touch these directories — Pod is responsible for
//! crate) must not touch these directories — Worker is responsible for
//! denying them at the Scope level when memory is enabled.
pub mod audit;
+2 -2
View File
@@ -1,6 +1,6 @@
//! Workspace memory resident-enumeration helpers.
//!
//! Surfaces used by the Pod system-prompt assembler:
//! Surfaces used by the Worker system-prompt assembler:
//!
//! - [`collect_resident_knowledge`] — resident-injection candidates
//! (`model_invokation: true`) returned as `(slug, description)` pairs.
@@ -8,7 +8,7 @@
//! `<workspace>/.yoi/memory/summary.md` when it parses as a summary
//! record and has non-empty body.
//! - [`list_knowledge_slugs`] — every slug whose file parses, regardless
//! of `model_invokation`. Used by the Pod IPC layer to answer TUI `#`
//! of `model_invokation`. Used by the Worker IPC layer to answer TUI `#`
//! completion (`model_invokation` is a resident-injection flag, not a
//! user-visibility flag).
//!
+1 -1
View File
@@ -1,7 +1,7 @@
//! Helpers for constructing `ScopeRule` entries that exclude the
//! memory tree from the generic CRUD tools' write surface.
//!
//! Pod is expected to call [`deny_write_rules`] when memory is enabled
//! Worker is expected to call [`deny_write_rules`] when memory is enabled
//! and append the result to the manifest's `scope.deny` list before
//! constructing the [`Scope`] passed to `tools::ScopedFs`. The memory
//! tools themselves bypass `ScopedFs` and write directly under the
+1 -1
View File
@@ -18,7 +18,7 @@
//! `.yoi/workflow/`.
//!
//! `memory.workspace_root` pins this root explicitly. Without an explicit
//! root, resolution searches upward from the Pod pwd for a `.yoi/memory`
//! root, resolution searches upward from the Worker pwd for a `.yoi/memory`
//! marker; `.yoi` project records alone are not a memory marker.
use std::path::{Path, PathBuf};