一個 session 為什麼需要唯一的 execution owner?
前幾天在 GitHub 看到 OpenClaw 的 PR「refactor: consolidate session input ownership and authority」,我翻了一下討論和變更範圍,第一個感覺不是「又一次大重構」,而是有人終於把 session input 最容易出錯的責任邊界攤在桌上講。這個 PR 在 2026-10-19 建立,目前已經有 55 則留言,動到 156 個檔案,還被標成 security-sensitive-changed 和 merge-risk security-boundary。光看這幾個標記,就知道它不是整理命名而已。
我自己寫 skill 和處理多來源輸入時,最常踩的坑其實不是正常路徑,而是 correction、retry、recovery 交疊的時候。某個 input 明明是有效修正,卻被當成一般訊息排隊;recovery 拿到 successor 的 source identity;一個已經 accepted 的 input,在 cleanup 或 replay 流程裡又被消費一次。每個單點看起來都像條件判斷漏寫,串起來卻是 authority 被悄悄轉移了。
這個 PR 最值得看的地方,是它把 session lifecycle 裡原本分散的 admission、execution、recovery、delivery 收斂到 SessionController,並且把幾個常被混在一起的結果拆開:
acceptance不等於consumption,收進來不代表已經安全地被執行。settlement要有明確 custody outcome,rejection、failed authority、accepted、unconfirmed consumption 不能共用同一條清理路徑。- source validity 和 target validity 分開判斷。來源有權限,不代表它對目前 target 仍然有效。
- accepted requester grant 綁定 exact run,只有 joined cleanup 才能釋放。
這幾點對 skill 開發者很實際。很多人設計 handler 時,只驗證「這個 sender 能不能做這件事」,但沒有驗證「這個 input 是否仍屬於這一次 execution」。當 execution owner 被 successor 偷換,或 queued completion work 在 dispatch 前失去 scope,原本正確的授權就可能變成 replay 入口。這不是單純的 concurrency bug,而是 lifecycle 與 security boundary 沒有使用同一套 ownership model。
我特別認同它對 human correction 的處理方式。相容且授權的修正,可以在支援的 boundary 加入 active execution,但不應該因此繼承或替換原本的 tools、workspace、model policy。也就是說,修正的是 input,不是整個執行上下文。這個界線如果沒有寫成 contract,最後通常會散落成幾個「看起來能跑」的 shortcut,等到 recovery 或 retry 才爆出來。
另外一個容易忽略的細節是 attachment。舊 attachment 擷取出來的 input 會被 fence,sender revocation 也不能讓同一份 input 重新 replay。這種規則在 happy path 幾乎感覺不到,但對 event-driven 系統來說,正是要靠這些負向保證,才能確定某個事件不會在另一條路徑死灰復燃。
不過這個 PR 現在還不能當成 OpenClaw 已經採用的既定行為。它仍在等待 exact-head hosted CI,以及 security/session-owner review。我會把它當成一份很好的架構審查材料來讀,特別是要理解如何把「誰可以送進來」、「誰負責執行」、「誰可以收尾」變成可驗證的 contract,而不是只靠幾個布林值和 try/catch。
如果你也在做 skill、queue 或 agent runtime,我建議直接拿自己的流程對照這四個問題:input 被誰接受?哪個 exact run 擁有它?什麼情況算 consumed?失敗之後 custody 交給誰?這四題答不清楚,問題通常只是還沒被 replay 出來而已。
作者:jiaweiOrz