yoi/.yoi/tickets/00001KW76E8EG/item.md

10 KiB

title state created_at updated_at assignee queued_by queued_at
Workspace Backendのembedded Runtimeをfs-store永続化に切り替える closed 2026-06-28T13:34:29Z 2026-06-28T19:16:51Z null workspace-panel 2026-06-28T17:12:16Z

背景

Workspace Backend の embedded Runtime は現在、EmbeddedWorkerRuntime::new_memory_with_execution_backend(...) で memory-backed Runtime として起動している。そのため Backend を再起動すると Runtime catalog、Worker snapshot、transcript、ConfigBundle store が失われる。

worker-runtime 側には既に fs-store backed Runtime が存在する。

  • Runtime::with_fs_store(...)
  • Runtime::with_fs_store_and_execution_backend(...)
  • FsRuntimeStoreOptions { root, runtime_id, display_name, limits }

一方で Workspace Backend 側の embedded wrapper には fs-store backed constructor が無く、WorkspaceApi::new_with_execution_backend(...) は memory-backed constructor を呼んでいる。

この Ticket では、Workspace Backend embedded Runtime を worker-runtime fs-store に接続し、Backend restart 後も Runtime record と transcript projection が残るようにする。

依存関係

  • 00001KW7726H9 Runtime Worker起動経路を正規のExecution/ConfigBundle経路に一本化する の設計に従う。
  • この Ticket は fs-store 接続と restart persistence を扱う。canonical create request の field 設計や旧 Pod store 削除はこの Ticket の主対象にしない。

調査済みの現状

Workspace Backend 側

  • crates/workspace-server/src/hosts.rs
    • WorkspaceApi::new_with_execution_backend(...)EmbeddedWorkerRuntime::new_memory_with_execution_backend(...) を呼んでいる。
    • embedded spawn path は WorkerSpawnRequest を Runtime CreateWorkerRequest に変換している。
  • crates/workspace-server/src/server.rs
    • ServerConfigworkspace_rootdatabase_path、host URLs などを持つ。
    • Runtime fs-store root はまだ持っていない。
  • crates/workspace-server/src/main.rs
    • WorkspaceIdentity::load_or_init(...) で workspace_id は取得済み。
    • 現状の ServerConfig::local_dev(...) には Runtime store root が渡されていない。
  • crates/workspace-server/Cargo.toml
    • worker-runtime dependency は features = ["ws-server"]
    • fs-store を使うには fs-store feature も有効化する必要がある。

worker-runtime 側

  • crates/worker-runtime/src/runtime.rs
    • Runtime::with_fs_store_and_execution_backend(options, backend) が存在する。
    • persisted state restore 時、Worker の live execution handle は復元せず WorkerExecutionStatus::unconnected() / execution_handle: None になる。
  • crates/worker-runtime/src/fs_store.rs
    • store root 配下に runtime_id 別の directory を作る。
    • runtime snapshot、worker snapshot、events、transcript entry を保存する。
  • crates/worker-runtime/src/config_bundle.rs
    • ConfigBundlemetadata.idmetadata.digest を持つ。
    • fs-store backed Runtime の persisted runtime state に ConfigBundle store も含まれる。

目的

  • Workspace Backend embedded Runtime を memory-backed から fs-store backed に切り替える。
  • Backend restart 後に Runtime catalog / Worker snapshot / transcript / ConfigBundle store が復元される。
  • live execution handle は再起動で復元できないものとして扱い、connected Worker のように見せない。
  • Runtime store root は Browser-facing API に出さない。
  • .yoi/tickets など project record と Runtime local state を混ぜない。

実装方針

1. workspace-server で worker-runtime fs-store feature を有効化する

crates/workspace-server/Cargo.tomlworker-runtime dependency に fs-store feature を追加する。

worker-runtime = { workspace = true, features = ["ws-server", "fs-store"] }

これにより Runtime::with_fs_store_and_execution_backend(...)FsRuntimeStoreOptions を Workspace Backend から使えるようにする。

2. Runtime store root を ServerConfig に持たせる

ServerConfig に embedded Runtime 用の store root を追加する。

候補名:

pub embedded_runtime_store_root: PathBuf

決定事項:

  • store root は Backend local state であり、Browser-facing API に出さない。
  • store root は .yoi/tickets 配下に置かない。
  • tests は temp dir を明示的に渡す。
  • CLI/default path は WorkspaceIdentity.workspace_id を使って workspace ごとに衝突しない path にする。

推奨 default:

<YOI_DATA_DIR or YOI_HOME or ~/.yoi>/workspace-server/<workspace_id>/worker-runtime

workspace-server crate が manifest::paths::data_dir() を使えない場合は、実装時に manifest dependency を追加するか、main.rs で default を解決して ServerConfig に注入する。workspace root 直下の git-tracked project record と混ぜないことを優先する。

3. EmbeddedWorkerRuntime に fs-store constructor を追加する

EmbeddedWorkerRuntime に fs-store backed constructor を追加する。

候補名:

EmbeddedWorkerRuntime::new_fs_store_with_execution_backend(...)

この constructor は内部で次を呼ぶ。

Runtime::with_fs_store_and_execution_backend(
    FsRuntimeStoreOptions {
        root: embedded_runtime_store_root,
        runtime_id: embedded_runtime_id,
        display_name,
        limits,
    },
    execution_backend,
)

runtime_id は embedded Runtime として安定した値にする。

  • 既存の EmbeddedWorkerRuntime::runtime_id() / embedded Runtime id 方針がある場合はそれに従う。
  • workspace ごとの identity は store root 側で分けるため、runtime_id に raw workspace path を入れない。
  • runtime_id が変わると既存 fs-store を復元できないため、restart 間で安定させる。

4. WorkspaceApi の constructor を fs-store backed に切り替える

WorkspaceApi::new_with_execution_backend(...) は memory constructor ではなく、fs-store constructor を呼ぶ。

変更前の趣旨:

EmbeddedWorkerRuntime::new_memory_with_execution_backend(...)

変更後の趣旨:

EmbeddedWorkerRuntime::new_fs_store_with_execution_backend(...)

この変更により、Workspace Backend 経由の embedded Runtime catalog / worker snapshot / transcript / ConfigBundle が fs-store に保存される。

5. restart 後の execution status を明示する

worker-runtime の restore は現状、Worker の live execution handle を復元せず WorkerExecutionStatus::unconnected() にする。これは正しい前提として扱う。

この Ticket では次を確認・必要に応じて補強する。

  • Backend restart 後の Worker は catalog / transcript 上は復元される。
  • live execution handle は復元済みのように見せない。
  • input-capable として扱えない場合は unconnected / stale execution mapping / typed diagnostic として表示・API 応答される。
  • restart 後に同じ WorkerId を使って fake response を生成しない。

6. ConfigBundle store の復元を確認する

fs-store backed Runtime は persisted runtime state に ConfigBundle store を持つ。Workspace Backend 側で embedded Runtime を fs-store に切り替えた後、Backend restart で ConfigBundle が失われないことを test で確認する。

この Ticket では ConfigBundle create API の再設計は行わない。00001KW7726H9 の canonical create 設計と矛盾しないよう、現行 store の復元だけを確認する。

Test plan

Focused tests を yoi-workspace-server 側に追加する。

embedded Runtime fs-store restore

  1. temp dir を store root として WorkspaceApi / embedded Runtime を起動する。
  2. Runtime に ConfigBundle を store する。
  3. Worker を作成し、transcript に entry を追加する。
  4. WorkspaceApi / Runtime を drop する。
  5. 同じ store root で WorkspaceApi / Runtime を再作成する。
  6. Runtime catalog に同じ Worker が復元されることを確認する。
  7. transcript entry が復元されることを確認する。
  8. ConfigBundle が復元されることを確認する。
  9. execution status が live connected として偽装されていないことを確認する。

memory-backed bypass absence

  • Workspace Backend の production constructor が new_memory_with_execution_backend(...) を呼ばないことを test または grep-resistant な unit test で確認する。
  • memory-backed Runtime は test helper / explicit in-memory constructor に限定する。

store root isolation

  • store root が ServerConfig から注入されることを確認する。
  • Browser-facing API response に store root が出ないことを確認する。
  • .yoi/tickets 配下を Runtime fs-store root にしないことを確認する。

受け入れ条件

  • crates/workspace-serverworker-runtimefs-store feature を有効化している。
  • ServerConfig が embedded Runtime store root を持ち、Workspace Backend 起動時に明示的に渡される。
  • CLI/default path が user data 配下の workspace_id 別 Runtime store root を使う。
  • EmbeddedWorkerRuntime に fs-store backed constructor が追加されている。
  • Workspace Backend の通常 constructor が EmbeddedWorkerRuntime::new_memory_with_execution_backend(...) を呼ばない。
  • embedded Runtime が Runtime::with_fs_store_and_execution_backend(...) を通って起動する。
  • Backend restart 後に Runtime catalog / Worker snapshot / transcript / ConfigBundle store が復元される。
  • restart 後の live execution handle は復元済みとして扱われず、unconnected / stale diagnostic として扱われる。
  • Browser-facing API に Runtime store root / raw path / execution handle が漏れない。
  • Focused tests が embedded fs-store restore、ConfigBundle restore、transcript restore、execution unconnected restore、memory-backed bypass absence を確認する。
  • cargo test -p yoi-workspace-server が通る。
  • cargo test -p worker-runtime --features ws-server,fs-store が通る。
  • cargo check -p yoi が通る。
  • git diff --check が通る。
  • nix build .#yoi --no-link が通る。

対象外

  • canonical Runtime Worker create request の field 確定。
  • per-worker cwd / tool scope の新 API。
  • remote Runtime execution provisioning。
  • live execution handle の restart 後自動再接続。
  • 旧 Pod store / pod-registry の削除。