fix(daemon): 移除資料夾要真的把雲端資料收回(arcrun-rag#46)
leo 2026-08-16 實撞:掛資料夾、同步完成、從清單按「移除」之後—— 「我去把 Logseq plugin 刪掉以後,**採集的 wiki 沒消失**」。 內容一筆都沒少,照樣搜得到、照樣 is_embedded=1、AI 照樣拿它回答。 真兇(源碼):app.go 的 RemoveFolder 全文只做三件事——從 WatchFolders 拿掉、 saveCfg、restartWatch,**一次都沒碰撤除**。而撤除機制本身是好的(在部署白名單裡、 有測試、direct.go 真的會觸發它),只是那兩個觸發點都在「還在監看的資料夾裡某個檔 被刪掉」的差異偵測迴圈裡。⇒ 刪一個檔會撤除 ✅/移除整個資料夾不會 ❌。 **在使用者眼裡是同一件事,在程式裡是兩條完全不同的路,只有一條接上了撤除。** 這不只是少一個功能:產品說明卡寫著「確保資料所有權完全屬於使用者而非 SaaS 供應商」,而使用者唯一看得到的收回動作不收回任何東西 ⇒ 知情同意的問題。 修法(沿用既有那條撤除路,不另寫一份): - drainPendingTakedowns:把既有的「待下架清單逐筆送出」抽成共用函式 - retireRootOnce:資料夾進 retiring_folders 後,把帳本裡真的上傳過的檔排進 既有的 PendingTakedowns、走同一條撤除路;撤乾淨才刪帳本 - 進度與失敗真因寫進 status.json(level-triggered),App 看到 done 才清設定 - App 是 config.json 的唯一寫入者(兩個行程都寫=互相蓋掉對方的設定) 邊界(本票最危險的地方):path 是相對於被監看資料夾的路徑 ⇒ 兩個資料夾各有 notes.md 時 page_name 與 path 完全相同,撤除一個會連坐另一個。撤除 payload 帶 library(逐根導出,與 ingest 同一個函式算的),workflow 兩個比對節點加「library 相符才殺」。只在兩邊都有 library 時才收緊 ⇒ 舊 daemon 不送/舊卡沒有都退回原行為。 畫面:舊文案「已經上傳的知識卡不會被刪除」技術上是對的,但它替使用者決定了他要的 是「只停止同步」。改成兩個選項各寫一行後果讓他選(預設待 leo 裁)。 測試:go test ./collector/... ./collector/cmd/arcrun-app/... 全綠; 新增 direct_retire_test.go(7)/remove_folder_takedown_test.go(4)/ workflows/tests/takedown-scope.test.mjs(8)。UI 用真 dist + headless Chrome 複驗, check-cis.sh/check-render.sh 全過。 ◐ 未做:真實例端到端(不可逆且 leo 正在該機器上工作,步驟已寫成清單等總管確認)/ workflow 要重新部署才生效/未重打 bundle、未出貨。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -40,6 +40,18 @@ type AccountSyncStatus struct {
|
||||
QuotaMessage *QuotaNotice `json:"quota_message,omitempty"`
|
||||
}
|
||||
|
||||
// RetiringStatus=某個「已移除、雲端撤除進行中」資料夾的現況(arcrun-rag#46)。
|
||||
//
|
||||
// 為什麼要有這個欄位:撤除可能跨好幾輪(節流+單輪上限+雲端可能剛好掛掉),
|
||||
// 使用者按下「移除並收回」之後如果畫面什麼都不說,他會以為又是一顆沒作用的按鈕
|
||||
// ——那正是這張票的病。⇒ 進度與**失敗的真因**都要看得見
|
||||
// (leo 2026-08-06:「別人的錯誤一律要顯示給用戶看,不然就會變成我的錯誤」)。
|
||||
type RetiringStatus struct {
|
||||
Remaining int `json:"remaining"` // 還有幾筆沒撤成功
|
||||
Done bool `json:"done"` // 已經收乾淨(App 看到才把設定裡那一筆清掉)
|
||||
LastError string `json:"last_error,omitempty"` // 最後一次失敗的真因(原文,不改寫)
|
||||
}
|
||||
|
||||
// SyncStatus 彙總每輪同步的萃取結果,持久化至 ~/.arcrun-rag/status.json。
|
||||
// 托盤依此決定顯示「已萃 N 檔」、「⚠ 萃取失敗 M 檔」還是「⚠ 萃取引擎未就緒」。
|
||||
type SyncStatus struct {
|
||||
@@ -67,6 +79,10 @@ type SyncStatus struct {
|
||||
// t104:per-account 狀態(key = instanceHostOf(cypher_url))
|
||||
AccountDetails map[string]AccountSyncStatus `json:"account_details,omitempty"`
|
||||
|
||||
// arcrun-rag#46:「移除並收回中」的資料夾進度(key=資料夾路徑)。
|
||||
// 與 SkippedDocs 同族——每輪照現況重算的快照,不進 CarryForwardActivity。
|
||||
Retiring map[string]RetiringStatus `json:"retiring,omitempty"`
|
||||
|
||||
// 🔴 G-6.2「不准安靜地略過」(2026-08-06):副檔名不在 allowedExt 的檔案,
|
||||
// 以前在 scan.go 的白名單閘就 `return nil` 蒸發了——沒事件、沒紀錄、沒畫面。
|
||||
// 使用者丟一份 .doc 進資料夾,得到的回應是**完全的沉默**。
|
||||
|
||||
Reference in New Issue
Block a user