feat(t210): 首頁改統計,不再逐檔解釋——Evan「9000/101/20 兜不起來」的病

地基(progress.go 的 SyncProgress/ClassifyFailure/BuildFailureBreakdown,
eeb35ba)已經算好「總量」與「失敗分類」,但沒人接到畫面上:首頁仍在用
本輪計數(extractedOK)+逐檔白話翻譯(humanizeFailure),導致 leo 08-08
轉述的病——三個數字互相對不起來,使用者無法判斷「還在跑」還是「壞了」。

接線(collector/direct.go):
- runDirectOnceRoot 現在也回傳這一根資料夾的 SyncProgress/StuckReasons
  (rootProgress),RunDirectOnce 跨帳號跨資料夾 Add() 累加成總量。
- G-6.2 的 SkippedDocCount(讀不了的檔,根本沒進 manifest)併進
  Unreadable/Total——這是 Progress() 算不到的部分,由呼叫端補齊,
  維持不變式 Total == Done+Pending+Stuck+Unreadable。
- 「送不上去」的分類統計=Stuck 的 LastError 原文+Unreadable 重用
  convert.go 既有的 ErrUnsupported,一起餵給 BuildFailureBreakdown。
  分類判斷全程只經過 progress.go 的 ClassifyFailure 一個接縫,
  direct.go/app.go/前端都不認得任何分類名稱字串(留給 t214 之後
  改資料驅動時只動一個檔)。
- SyncStatus 新增 Progress/FailureBreakdown 兩個欄位,兩者都是每輪從
  manifest/掃描結果原地重算的現況快照,不進 CarryForwardActivity——
  斷網或閒置一輪不會被清成 0。

畫面(cmd/arcrun-app/app.go+frontend/src/main.js):
- 移除 humanizeFailure/buildFailures/UIFailures 那套逐檔白話翻譯,
  改用 UIProgress(Total/Done/Pending/CantSync/Groups);前端 cardProgress
  只把後端給的 category/count 陣列原樣印出,不分支、不排序、不認分類名。
- 「送不上去」預設摺疊(<details>),展開只有分類與份數,不逐檔列名、
  不解釋、不給解法;細節導向「開啟使用說明」。
- 保留 buildSkipped 的「讀不了的檔」卡片(那是另一件事),但份數已併入
  Unreadable。
- 移除「總計」卡片裡用本輪計數 extractedOK 的「份已整理」——上方狀態
  時間軸的「上次 N 份」與下方矛盾(1 份 vs 0 份已整理)的病因直接消掉,
  改用 cardProgress 的累計「已送上去」。

驗證:
- go build ./... 與 go test ./...(collector/cmd/arcrun-app/
  cmd/arcrun-tray 三個 module)全綠。
- 新增 collector/progress_wiring_test.go:真跑 RunDirectOnce 湊出
  Done/Pending/Stuck/Unreadable 四種狀態同時存在,驗四數字相加等於
  總數(leo 驗法①);再跑一輪「什麼都沒發生」驗數字不歸零(驗法③)。
- check-render.sh 視覺機械閘綠(lockup 底板/深色模式)。

殘項(誠實標記,未完成):
- 真機驗收(leo 08-08 驗法④:拿 Evan 的情境走一遍)未做,需要 leo 或
  封測者在實機驗證。
- 「開啟使用說明」目前連到既有 docs 首頁,尚無 t210 分類對應的 FAQ 頁
  (tasks.md 已記為相依項)。
- t213 診斷檔尚未消費這組新欄位(tasks.md 記載該任務等本任務讓路)。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-08 12:45:12 +08:00
parent 1efc8123f1
commit b3f63f40fb
6 changed files with 333 additions and 170 deletions
+16
View File
@@ -72,6 +72,22 @@ type SyncStatus struct {
// leo 08-06 封測者放了 .md 說「無法通過」,畫面只有「有 1 個不是文件的檔案」,
// 沒人判斷得出那到底是什麼檔。
SkippedOtherNames []string `json:"skipped_other_names,omitempty"`
// ── t210 統計層(2026-08-08Evan 封測:「9000 個檔,雲端只有 101 張卡,
// 畫面卻說 20 份沒送——這幾個數字到底是怎麼回事?」)──────────────────────
//
// Progress=總量進度快照(見 progress.go 的 SyncProgress(*Manifest).Progress())。
// 由 RunDirectOnce 跨帳號、跨資料夾 Add() 累加,並把 G-6.2 的 SkippedDocCount
// 併進 UnreadableTotalProgress() 算不到「根本沒進 manifest」的檔)。
//
// FailureBreakdown=「送不上去」(Stuck+Unreadable)展開後的分類統計——
// 只有分類與份數,沒有檔名、沒有解法(取代 08-06 那套逐檔 humanizeFailure)。
//
// ⚠️ 與 SkippedDocCount 同類,**都不進 CarryForwardActivity**manifest 每輪
// 重建、涵蓋現況所有檔,這裡原地算出來就是對的——也因此斷網/閒置一輪後
// 不會被清成 0(現況快照,不是本輪計數)。
Progress SyncProgress `json:"progress"`
FailureBreakdown FailureBreakdown `json:"failure_breakdown"`
}
// MaxSkippedListedstatus.json 裡最多逐檔列幾個。