部落格
通知不該只打開 App,它應該把你帶回正確的 Session
推播通知不是「送到了」就算完成。對多會話 AI 程式工作來說,通知必須帶著正確的 server、session 與目前狀態一起到達。1.6.6 修的就是這條上下文回流鏈路。
繼續查看該欄目下的產品與工程更新。
瀏覽此分類我們通常把通知理解成一個送達問題:到了沒有、快不快、能不能上鎖屏。對遠端 AI 程式工作來說,這個定義太淺了。
如果一則通知只能做到「把 App 打開」,那它並沒有真正閉合回饋環。你還是得自己重建現場:這是哪台機器、哪個會話、Claude 是在要求批准還是回報完成,以及它對應的是你現在看的任務,還是稍早留在背景跑的另一個 session。
這不是文案問題,也不是轉場動畫問題,而是一個完整的狀態同步問題。
為什麼這在 AI 程式場景裡更嚴重
在很多一般 App 裡,一則通知通常只對應一個物件:一封郵件、一則訊息、一個行事曆事件。你點進去之後,目標實體天然就是明確的。
遠端 AI 程式工作不是這樣。
你可能同時有三個 session 在跑:
- 一個在重構某個模組
- 一個在等測試結果
- 另一個停在權限批准上
在這種情況下,「Claude 需要你」這句話根本不夠。真正重要的是:
- 哪台 server 發出這則通知
- 哪個 session 觸發了它
- 那個 session 目前處於什麼狀態
- 使用者現在是否已經在看這個 session
只要其中一項缺失,通知就會退化成模糊提醒。它能打斷你,卻不能幫你決策。
通知失效,不只是不見,也可能是帶你到錯的地方
很多系統把通知可靠性理解成「盡量不要掉」。但在多會話工作流裡,另一種一樣糟糕的失敗方式是:通知到了,卻把你帶回錯誤的上下文。
這類失敗比完全收不到更隱蔽,也常常更危險。
因為使用者會以為自己已經回到正確位置,接著就在錯誤的 session 上繼續操作。對遠端 AI 程式工作來說,這可能意味著:
- 在錯誤的 repo 裡回覆 Claude
- 給錯誤的任務做批准
- 把另一個 session 的狀態誤判成目前任務的狀態
從互動層看,這像是一次普通跳轉錯誤;從產品層看,它破壞的是整套遠端工作流的信任。
要讓通知真正有用,上下文必須活過整條鏈路
一則有用的通知,不只是一個 APNs payload。它必須穿過完整鏈路,而且在每一段都不能遺失身分:
- 當 server hook 事件產生時,要知道是哪個
tmux_session觸發 - 當 server 廣播通知時,要把
session一起帶出去 - 當 push relay 去重時,不能只按 project 去重,不然不同 session 會互相吞掉
- 當 App 冷啟動時,要能把 push 裡的 server identity 映射回本地儲存的 server
- 當最終導覽發生時,要先回到正確 server,再選中正確 session,而不是落到預設頁
只要其中一段退化成「盡量猜」,最後行為就會不穩定。
這也是為什麼 1.6.6 裡和通知相關的改動,看起來分散在 iOS、Mac、server 與 push relay,但它們本質上都在修同一件事:把通知從泛泛提醒,變成可執行的上下文入口。
舊模型到底是怎麼壞掉的
如果把問題抽象一下,舊模型主要有四種常見失效方式。
1. 事件源有 session,通知卻沒有 session
Server 上的 hook 事件明明知道自己來自某個 tmux_session,但通知廣播只說「有一則通知」,沒有把 session 一起傳下去。到了客戶端,系統就只能退化成「先回當前頁再說」。
這會製造一個很危險的錯覺:通知點開後的確有跳,看起來像功能存在,但實際落點常常是錯的。
2. 前景可用,不代表冷啟動可用
很多通知跳轉在 App 還活著時都沒問題,真正難的是冷啟動。因為這時 App 還沒恢復完整狀態。
在那一刻,server 列表可能還在載入,導覽狀態可能還不存在,本地 ID 也未必和 push payload 裡的識別一致。如果太早驅動導覽,通常只會得到兩種結果:
- 什麼都沒跳
- 有跳,但跳到錯的 server 或 session
3. 去重邏輯錯把兩個 session 當成同一事件
如果 push relay 的 dedupe key 只包含 server + project + event,沒有把 session 算進去,那麼同一個專案裡兩個 session 在接近時間內觸發事件時,後一則通知就可能被前一則吞掉。
這不會長得像 crash,卻會長成最難查的使用者抱怨:「明明完成了,為什麼我沒收到通知?」
4. 客戶端把「目前可見 session」誤當成「通知來源 session」
這是多會話產品裡很典型的建模錯誤。UI 目前聚焦在哪個 session,和剛才發出通知的是哪個 session,本來就不是同一概念。如果狀態層沒有把它們拆開,跳錯幾乎是必然結果。
1.6.6 真正修的不是一個按鈕,而是一條路徑
這次版本裡真正重要的,不是「支援點擊通知跳轉」這句話,而是幾個原本斷開的約束終於被串了起來。
1. 通知現在會攜帶 session 身分
以前一個事件明明屬於 session B,但客戶端只知道「有通知發生」,最後就退回 session A。1.6.6 讓 session 身分穿過通知廣播與 push payload。現在通知不再只是「Claude 有事找你」,而是「repo-x / session-y 有事找你」。
2. 冷啟動不再更容易丟 deep link
真正難的不是頁面怎麼跳,而是身分怎麼對。push 帶來的是 server 端 identity;App 裡保存的是本地物件 ID。只有把這兩套身分系統對上,冷啟動跳轉才算真的成立。
換句話說,問題不在「怎麼切頁」,而在「系統怎麼證明這就是同一台 server」。
3. Push 投遞不再把 session 當成附屬欄位
如果 dedupe key 裡沒有 session,那兩個不同 session 就可能互相壓掉。這說明了一件事:在 AI 工作流裡,session 不是附屬 metadata,而是通知語義本身的一部分。
4. 本地通知、遠端 push 與頁面導覽終於開始說同一種語言
通知鏈路最怕的是三層各說各話:
-
server 說「這是 hook 事件」
-
push 服務說「這是一則 project 級通知」
-
客戶端說「那我先回當前頁」
1.6.6 最重要的價值之一,就是這三層開始對齊到同一個目標:把使用者帶回產生該事件的 server 與 session。
為什麼這是產品問題,不只是工程問題
表面上我們一直在談 ID、payload 與 deep link。但底下其實有一個更大的產品判斷:
通知是否應該被設計成「把使用者帶回需要做決策的正確現場」的機制?
如果答案是是,那送達率就不夠了。一則通知必須同時滿足三個條件:
- 它有到
- 它落在對的地方
- 它落地之後,使用者可以立刻採取下一步動作
用這個標準來看,很多產品裡的通知其實只做到第一條。
使用者真正感受到的變化是什麼
如果完全不看內部實作,只從日常使用來看,1.6.6 至少改善了四個結果:
- 點開通知後,更少落到錯的 session
- 從鎖屏或已終止狀態喚起 App 時,更少遺失上下文
- 瞬時網路失敗更不容易直接吃掉通知
- Live Activity 在異常路徑裡的狀態更可信,即使 force-quit 邊界仍然存在
這四件事單看都不花俏,但它們一起回答了一個更重要的問題:你到底敢不敢真的把多個 AI session 掛在背景跑。
可靠也意味著要誠實面對邊界
1.6.6 也重寫了 Live Activity 的清理路徑:重新啟動時會回收陳舊 activity、清理孤兒參照,並降低短暫斷線後錯誤顯示「Finished」的機率。
但有一個邊界情況我們沒有假裝它已經被完全解決:如果使用者強制結束 iOS App,Live Activity 仍可能停留到下次啟動或系統 timeout。
如果我們把這件事包裝成「完全修好」,文案也許會比較漂亮,但產品會變得更不可信。對開發者工具尤其如此,因為你賣的不是氣氛,而是可預期性。
真正的目標不是更多通知
好的遠端 AI 產品,不應該要求使用者每次收到通知後都重新理解一次「剛才到底發生了什麼」。
通知真正該做的,是提前幫你把恢復上下文這件事做掉。
對遠端 AI 程式工作來說,送達只是入場券。通知能不能帶著完整上下文一起到達,才決定了它究竟是有用輸入,還是又一次打斷。
1.6.6 沒有發明通知,也沒有發明多會話。它做的是更基礎、也更重要的一件事:讓這兩者終於能正確協同工作。