yoi/tickets/scope-exclusion.md
2026-04-14 12:09:18 +09:00

4.9 KiB
Raw Blame History

複数 Pod 間の Scope 排他制御

背景

scope-redesign.md で Scope は「allow / deny の領域リスト + permission レベル」に再設計された。 これにより複数 Pod が同じファイルツリーに対して異なる権限を宣言する状況が日常化する。

現状、複数 Pod が同じ pwd や重なる allow を持っても何のチェックも警告もない。 両者が同じファイルに write を持っていた場合、ツール経由で同時に書き換えて 内容を破壊しうる。Git のコミット粒度より細かい競合は履歴からも復元しづらい。

Pod を「並行作業の単位」として扱う以上、scope の重なりは設計時に検知・制御 できる必要がある。

要件

  • R1: write の重複を検出する 同じファイルが 2 つ以上の Pod から write 権限で見えている状態を作らせない。 片方の Pod が起動中なら、もう片方の起動を拒否する(または昇格を拒否する)。

  • R2: read は共有可 read のみの重なりは許す。複数の閲覧者は問題ない。

  • R3: deny は重なりに影響しない deny で write が落とされている path は、その Pod にとって write を持たないと みなして他 Pod との重複判定を行う。

  • R4: 解放の確実性 Pod の異常終了で排他が永久に残らないこと。lock の所有者プロセスが死んだら 自動解放されるか、stale lock として検知できる。

  • R5: 観測可能性 ユーザーが「今どの Pod がどこを write 占有しているか」を見られる。 競合で起動が拒否されたとき、競合相手をエラーメッセージで示す。

設計上の論点

排他の粒度

選択肢:

  • A. ファイル単位 — 厳密だが lock 数が膨大になる
  • B. allow rule 単位 — 宣言された target ごとに lock。粒度が荒いが宣言と一致して直感的
  • C. パス prefix の最小被覆 — write 領域を最小の prefix に縮約して lock。中間

おすすめは B。Pod の宣言と lock の単位が一致する方が説明しやすく、 ユーザーが「この Pod は src を握っている」と理解しやすい。

lock の保管場所

選択肢:

  • A. lock file~/.insomnia/locks/<hash>.lock 等。各 Pod プロセスが直接握る
  • B. 中央レジストリプロセス — 常駐デーモンが scope の貸し借りを管理
  • C. session-store の拡張 — 既存の永続化基盤に lock テーブルを足す

おすすめは A。デーモンを増やしたくないし、Pod は短命〜中時間生存の想定なので ファイルロック (flock(2) / fcntl) で十分。stale lock 検知は PID 死活で行う。

競合発生時の挙動

選択肢:

  • A. 起動失敗 (fail-fast) — エラーで起動拒否、ユーザーが手で解決
  • B. 待機 (block) — 競合相手が解放するまで起動を待つ
  • C. 自動降格 — 競合する write を read に降格して起動

おすすめは A。並行作業の単位として Pod を起動するなら、競合は意図しない 状況であることが多い。明示エラーで気づける方が安全。--wait フラグや --read-only フラグで B / C を選べるようにするのは将来拡張で十分。

取得タイミング

  • Pod 起動時に scope 全体を一括取得し、終了時に解放
  • 起動中に scope を変えることは現状想定しないmanifest 編集 → 再起動)

resume との関係

Pod::restore でも同じ scope が要求される。前回終了時に解放されているはずなので 取得が成功するのが正常。失敗する場合は別 Pod が起動している = ユーザーが意図的に 2 つ動かそうとしている。fail-fast に乗せる。

影響範囲(想定)

実装時に詰める。現時点での見立て:

  • 新規モジュール crates/pod/src/scope_lock.rs(または独立クレート scope-lock
    • lock の取得 / 解放
    • stale lock 検知PID 確認)
    • 競合情報の収集(誰がどの allow を握っているか)
  • Pod::new / Pod::restore の前段で lock 取得
  • Pod の Drop / 明示解放で lock 返却
  • Controller 層でのエラー伝搬とユーザー向けメッセージ
  • CLI に「現在のロック一覧」を見るコマンド(観測性 R5

非ゴール

  • 同一 Pod 内の並行性制御 — 1 Pod 内のツール並行実行は本 ticket では扱わない
  • ネットワーク越しの排他 — ローカルファイルロックのみ。複数マシンで同じワーキングコピーを共有する想定はしない
  • read-write lock の細かな格上げ/格下げ — 取得時に確定、起動中の変更はしない

依存