fix(console): 駕駛艙「今日完成」跨 UTC 日界修正——today_done 0/10 假空(07b 板實態 3 個 parser 落差) #40

Merged
Leo merged 1 commits from fix/console-today-write-dayline into main 2026-07-08 14:02:06 +00:00
Owner

根因

live 症狀(2026-07-08 21:40 台北實測 GET /console/dashboard-data):today_done:0, today_total:10, done_today_titles:[],但 sprint-2026-07b.md 今晨台北 05:50(=UTC 07-07 21:50)已勾 CP1/T7(+T5-provider)。

任務板 parser(cypher-executor/src/lib/console-dashboard-model.ts)與 07b 實際維護慣例的三個落差

  1. 完成日期 regex 太窄(舊 COMPLETED_DAY = /完成((\d{4}-\d{2}-\d{2})/,原 L262):要求日期緊貼「完成(」。07a 慣例日期在前(完成(2026-07-02,[cloud-worker]))PR#37 測過;07b 起署名在日期前完成([cloud-worker] 2026-07-07,…),07b L45 T7)→ 抓不到 → [x] 無日期=「不冒領」把整項蒸發。
  2. 完成標記寫在縮排子彈上不被掃(舊 parser 只 match 行首 checkbox 行,原 L305-321):CP1(07b L31)/T5-provider(07b L29)的任務行只有 [x],完成註記整段在子彈上 → 同樣蒸發。
  3. 跨 UTC 日界:cloud-worker sandbox 時鐘是 UTC、routine 排程台北清晨(06:30=UTC 前一日 22:30)——它戳的日期 2026-07-07 其實是台北 07-08 凌晨的完成,completed_days.includes(todayKey)(原 L340)永遠對不上。PR#37 的「時區統一台北」只統一了讀側,沒吃到寫手時鐘的日界。

(附帶同根因:[🔄→只剩1042](07b L20 T5-graph)不匹配舊單字元狀態 regex → 任務蒸發、today_total 少算。)

修法(全在純函式層,route 零改動)

  • DONE_STAMP 抓「完成(…)」括號內容、日期允許前綴;縮排補充行的完成標記歸到所屬任務(子彈本身仍不是任務,「做法:/驗收:」不會誤收)。
  • [cloud-worker] 署名戳 D 展開台北候選日 {D, D+1};progress-guard 跑台北 16:30(UTC 同日)不展開——展開只會多冒領;本機/總管台北戳照舊精確,既有「跨台北午夜不冒領」測試不動照綠。
  • 狀態欄放寬 \[([^\]]*)\]classifyBoardMark🔄/! 帶註記照認;x 帶註記仍不冒領 done(寬鬆容錯原則不變)。
  • 快取形狀不變(completed_daysstring[],展開在 parse 側)——跨午夜快取安全性與 #36/#37 設計不動。

測試證據

修前紅(新增 5 案例重現 live 症狀):

FAIL  07b 跨 UTC 日界 live bug > UTC 昨天 21:50=台北今天 05:50
AssertionError: expected [] to deeply equal ArrayContaining{…}
- ArrayContaining [ "T5-provider(LLM 換源 Gemini recipe)", "CP1(content-pipeline 多出口架構驗證)", "T7 golden questions 框架" ]
+ []
Tests  3 failed | 24 passed (27)

修後綠

✓ tests/console-dashboard-model.test.ts (27 tests)
Tests  27 passed (27)

全套:vitest 87/88——唯一失敗=pre-existing executor.test.ts 不存在的零件(PR#37 已記錄同一筆,stash 於未改樹複驗同樣紅)。tsc 錯誤行數與未改樹相同(12 行,全在 validate/webhooks-named,workers-types 環境漂移,非本次引入)。

live 檔實證:Gitea 現行 07a+07b 檔直灌新 parser → today_done:3, done_today_titles:[T5-provider, CP1, T7],T5-graph 以 doing 回到板上=板上真相。

SDD:system-dev/docs/3-specs/arcrun/search-console/tasks.md task 5.6(本次新增)。未部署(紅線;端到端 curl 驗證留 task 5.5 總管跑)。

[總管-subagent]

## 根因 live 症狀(2026-07-08 21:40 台北實測 `GET /console/dashboard-data`):`today_done:0, today_total:10, done_today_titles:[]`,但 sprint-2026-07b.md 今晨台北 05:50(=UTC 07-07 21:50)已勾 CP1/T7(+T5-provider)。 任務板 parser(`cypher-executor/src/lib/console-dashboard-model.ts`)與 07b 實際維護慣例的**三個落差**: 1. **完成日期 regex 太窄**(舊 `COMPLETED_DAY = /完成((\d{4}-\d{2}-\d{2})/`,原 L262):要求日期緊貼「完成(」。07a 慣例日期在前(`完成(2026-07-02,[cloud-worker])`)PR#37 測過;**07b 起署名在日期前**(`完成([cloud-worker] 2026-07-07,…)`,07b L45 T7)→ 抓不到 → `[x]` 無日期=「不冒領」把整項蒸發。 2. **完成標記寫在縮排子彈上不被掃**(舊 parser 只 match 行首 checkbox 行,原 L305-321):CP1(07b L31)/T5-provider(07b L29)的任務行只有 `[x]`,完成註記整段在子彈上 → 同樣蒸發。 3. **跨 UTC 日界**:cloud-worker sandbox 時鐘是 UTC、routine 排程台北清晨(06:30=UTC 前一日 22:30)——它戳的日期 `2026-07-07` 其實是台北 07-08 凌晨的完成,`completed_days.includes(todayKey)`(原 L340)永遠對不上。PR#37 的「時區統一台北」只統一了**讀側**,沒吃到**寫手時鐘**的日界。 (附帶同根因:`[🔄→只剩1042]`(07b L20 T5-graph)不匹配舊單字元狀態 regex → 任務蒸發、today_total 少算。) ## 修法(全在純函式層,route 零改動) - `DONE_STAMP` 抓「完成(…)」括號內容、日期允許前綴;縮排補充行的完成標記歸到所屬任務(子彈本身仍不是任務,「做法:/驗收:」不會誤收)。 - `[cloud-worker]` 署名戳 D 展開台北候選日 `{D, D+1}`;progress-guard 跑台北 16:30(UTC 同日)**不展開**——展開只會多冒領;本機/總管台北戳照舊精確,既有「跨台北午夜不冒領」測試不動照綠。 - 狀態欄放寬 `\[([^\]]*)\]`+`classifyBoardMark`:`🔄/!` 帶註記照認;**x 帶註記仍不冒領 done**(寬鬆容錯原則不變)。 - 快取形狀不變(`completed_days` 仍 `string[]`,展開在 parse 側)——跨午夜快取安全性與 #36/#37 設計不動。 ## 測試證據 **修前紅**(新增 5 案例重現 live 症狀): ``` FAIL 07b 跨 UTC 日界 live bug > UTC 昨天 21:50=台北今天 05:50 AssertionError: expected [] to deeply equal ArrayContaining{…} - ArrayContaining [ "T5-provider(LLM 換源 Gemini recipe)", "CP1(content-pipeline 多出口架構驗證)", "T7 golden questions 框架" ] + [] Tests 3 failed | 24 passed (27) ``` **修後綠**: ``` ✓ tests/console-dashboard-model.test.ts (27 tests) Tests 27 passed (27) ``` **全套**:vitest **87/88**——唯一失敗=pre-existing `executor.test.ts 不存在的零件`(PR#37 已記錄同一筆,stash 於未改樹複驗同樣紅)。tsc 錯誤行數與未改樹相同(12 行,全在 validate/webhooks-named,workers-types 環境漂移,非本次引入)。 **live 檔實證**:Gitea 現行 07a+07b 檔直灌新 parser → `today_done:3, done_today_titles:[T5-provider, CP1, T7]`,T5-graph 以 doing 回到板上=板上真相。 SDD:`system-dev/docs/3-specs/arcrun/search-console/tasks.md` task 5.6(本次新增)。**未部署**(紅線;端到端 curl 驗證留 task 5.5 總管跑)。 [總管-subagent]
Leo added 1 commit 2026-07-08 13:52:27 +00:00
SDD:system-dev/docs/3-specs/arcrun/search-console/tasks.md task 5.6(本次新增,Phase 5 稽核輪延伸)

live bug(2026-07-08 21:40 台北實測):sprint-2026-07b.md 台北今晨 05:50
(=UTC 07-07 21:50,cloud-worker 跨 UTC 日界寫入)勾了 CP1/T7/T5-provider,
/console/dashboard-data 卻回 today_done:0/today_total:10、done_today_titles:[]。

根因=任務板 parser 與 07b 實際維護慣例的三個落差(lib/console-dashboard-model.ts):
1. COMPLETED_DAY 要求日期緊貼「完成(」——07b 起署名在日期前
   (「完成([cloud-worker] 2026-07-07,…)」)→ T7 的完成日抓不到,
   [x] 無日期=整項蒸發(不冒領原則誤傷)。
2. 完成標記寫在縮排子彈上(CP1/T5-provider 的任務行只有 [x])→ 舊 parser
   只掃行首 checkbox 行 → 同樣蒸發。
3. cloud-worker sandbox 時鐘是 UTC、routine 排程台北清晨(06:30=UTC 前一日
   22:30)——它戳的日期 D 其實是台北 D+1 凌晨的完成,todayKey 永遠對不上。

修法(全在純函式層,route 零改動):
- DONE_STAMP 改抓「完成(…)」括號內容、日期允許前綴;縮排補充行的完成
  標記歸到所屬任務(子彈本身仍不是任務)。
- [cloud-worker] 署名戳 D 展開台北候選日 {D, D+1};progress-guard 跑台北
  16:30(UTC 同日)不展開——展開只會多冒領;本機/總管台北戳照舊精確,
  「昨天完成的明天不冒領」不變。
- 狀態欄放寬:[🔄→只剩1042](07b 實例)認 doing,任務不再蒸發、today_total
  不再少算;x 帶註記仍不冒領 done(寬鬆容錯原則不變)。

驗證:新增 5 案例(07b 逐字真實形態)修前紅(today_done:0、done_today_titles
[]=live 症狀重現)修後綠;model 測試 27/27;全套 vitest 87/88(1 失敗=
pre-existing executor「不存在的零件」,stash 於未改樹複驗同樣紅);tsc 錯誤
行數與未改樹相同(12 行,全在 validate/webhooks-named,workers-types 環境
漂移,非本次引入);另用 Gitea live 07a+07b 檔直灌新 parser:today_done:3、
done_today_titles=[T5-provider, CP1, T7]=板上真相。不部署(留 task 5.5)。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Leo merged commit 2fa0974e1c into main 2026-07-08 14:02:06 +00:00
Sign in to join this conversation.