936 Commits

Author SHA1 Message Date
ogt
6952d2d926 fix(import): fail auto import on drive auth failure 2026-06-25 09:31:11 +08:00
ogt
84035906ab fix(import): fail daily sales job on monthly sync failure
All checks were successful
CD Pipeline / deploy (push) Successful in 1m3s
2026-06-24 21:56:24 +08:00
ogt
8240b59b84 fix: add webcrumbs loader fallback
All checks were successful
CD Pipeline / deploy (push) Successful in 1m4s
2026-06-24 21:26:10 +08:00
ogt
5adeacd65c fix: route formal homepage to growth command center
All checks were successful
CD Pipeline / deploy (push) Successful in 1m3s
2026-06-24 21:18:09 +08:00
ogt
65aa23800c fix: keep growth detail row highlighted from action plan
All checks were successful
CD Pipeline / deploy (push) Successful in 1m3s
2026-06-24 21:02:19 +08:00
ogt
fa71897158 feat: add growth daily action plan
All checks were successful
CD Pipeline / deploy (push) Successful in 1m2s
2026-06-24 21:00:05 +08:00
ogt
9610b4da18 feat: add growth sales playbook board
All checks were successful
CD Pipeline / deploy (push) Successful in 1m2s
2026-06-24 20:51:11 +08:00
ogt
2aa1ae04ed feat: add growth category strategy board
All checks were successful
CD Pipeline / deploy (push) Successful in 1m3s
2026-06-24 20:46:15 +08:00
ogt
b87931c911 feat: add growth product decision panel
All checks were successful
CD Pipeline / deploy (push) Successful in 1m3s
2026-06-24 20:41:39 +08:00
ogt
7cfca93754 feat: add growth detail search and sort
All checks were successful
CD Pipeline / deploy (push) Successful in 1m5s
2026-06-24 20:23:25 +08:00
ogt
7180c0f817 feat: add growth action summary
All checks were successful
CD Pipeline / deploy (push) Successful in 1m16s
2026-06-24 20:05:58 +08:00
ogt
2d9acfdc5c feat: show price evidence in growth details
All checks were successful
CD Pipeline / deploy (push) Successful in 1m12s
2026-06-24 19:59:46 +08:00
ogt
776a7dd4ea feat: add growth strategy split cards
All checks were successful
CD Pipeline / deploy (push) Successful in 1m3s
2026-06-24 15:53:50 +08:00
ogt
873e0ce902 feat: add growth dashboard drilldown details
All checks were successful
CD Pipeline / deploy (push) Successful in 1m5s
2026-06-24 15:28:53 +08:00
ogt
e6deaa4711 feat: link growth dashboard metrics to details
All checks were successful
CD Pipeline / deploy (push) Successful in 1m6s
2026-06-24 14:28:17 +08:00
ogt
06418878e0 feat: add momo review candidate queue
All checks were successful
CD Pipeline / deploy (push) Successful in 1m11s
2026-06-24 13:09:56 +08:00
OoO
76a89a7098 fix: tolerate missing quantities for review candidates
All checks were successful
CD Pipeline / deploy (push) Successful in 1m2s
2026-06-19 02:48:23 +08:00
OoO
4b0a331d98 feat: persist targeted momo review candidates
Some checks failed
CD Pipeline / deploy (push) Failing after 35s
2026-06-19 02:43:34 +08:00
OoO
bed4488a72 fix: pick best targeted momo offer per pchome item
All checks were successful
CD Pipeline / deploy (push) Successful in 1m4s
2026-06-19 00:55:35 +08:00
OoO
9d84cbfd43 feat: deepen pchome momo backfill guardrails
All checks were successful
CD Pipeline / deploy (push) Successful in 1m8s
2026-06-19 00:41:20 +08:00
OoO
4c59b74ced feat: schedule growth momo backfill
All checks were successful
CD Pipeline / deploy (push) Successful in 1m11s
2026-06-19 00:18:53 +08:00
OoO
9ca8d4e43c feat: backfill growth momo matches
All checks were successful
CD Pipeline / deploy (push) Successful in 1m9s
2026-06-18 16:02:02 +08:00
OoO
6d6f3b473f chore: bump dashboard version to v10.633
All checks were successful
CD Pipeline / deploy (push) Successful in 1m6s
2026-06-18 15:21:26 +08:00
OoO
8fb908cf4a fix: preserve growth task label
All checks were successful
CD Pipeline / deploy (push) Successful in 1m2s
2026-06-18 15:18:34 +08:00
OoO
89407b054f feat: add pchome growth command center
All checks were successful
CD Pipeline / deploy (push) Successful in 1m10s
2026-06-18 15:14:38 +08:00
OoO
8145c227c7 fix: sanitize excel export values
All checks were successful
CD Pipeline / deploy (push) Successful in 1m7s
2026-06-18 14:58:32 +08:00
OoO
c83fb4cfa9 fix: skip missing code review ollama models
All checks were successful
CD Pipeline / deploy (push) Successful in 1m5s
2026-06-18 14:34:53 +08:00
OoO
ba5fe06b13 fix: update ollama primary host
Some checks failed
CD Pipeline / deploy (push) Has been cancelled
2026-06-18 14:24:55 +08:00
OoO
37f1802274 fix: clean stale partial database backups
All checks were successful
CD Pipeline / deploy (push) Successful in 1m8s
2026-06-18 13:51:15 +08:00
OoO
bd942e9427 fix: skip unhealthy direct ollama probes
All checks were successful
CD Pipeline / deploy (push) Successful in 1m10s
2026-06-18 13:46:30 +08:00
OoO
ee50e440ce fix: rescue gcp ollama through proxy
All checks were successful
CD Pipeline / deploy (push) Successful in 1m9s
2026-06-18 12:13:38 +08:00
OoO
9bafa73ffc fix: defer embedding work during gcp backoff
All checks were successful
CD Pipeline / deploy (push) Successful in 1m10s
2026-06-18 12:06:24 +08:00
OoO
56cd883148 fix: gate elephant price decisions to HITL
All checks were successful
CD Pipeline / deploy (push) Successful in 2m11s
2026-06-18 10:14:46 +08:00
OoO
08532b2987 feat: improve pchome growth UX workbench
All checks were successful
CD Pipeline / deploy (push) Successful in 1m5s
2026-06-16 12:03:29 +08:00
OoO
3c0e558fbe V10.622 refresh growth cache after offer sync
All checks were successful
CD Pipeline / deploy (push) Successful in 1m3s
2026-06-16 11:49:06 +08:00
OoO
01c73e02a2 V10.621 sync auto candidates to growth layer
Some checks failed
CD Pipeline / deploy (push) Failing after 34s
2026-06-16 11:41:34 +08:00
OoO
15010ab724 V10.620 automate unit price candidates
All checks were successful
CD Pipeline / deploy (push) Successful in 1m5s
2026-06-16 11:27:12 +08:00
OoO
7a2520dc67 V10.619 MOMO 精準候選搜尋
All checks were successful
CD Pipeline / deploy (push) Successful in 1m5s
2026-06-16 11:13:24 +08:00
OoO
4d1a664678 V10.617 AI 情報頁作戰導向 UI
All checks were successful
CD Pipeline / deploy (push) Successful in 1m5s
2026-06-16 10:55:43 +08:00
OoO
11b9ea6fef V10.616 主商品看板繁中化
All checks were successful
CD Pipeline / deploy (push) Successful in 1m5s
2026-06-16 10:24:24 +08:00
OoO
eb521fd6d8 V10.615 AI 推薦頁 Ollama 主路徑文案
All checks were successful
CD Pipeline / deploy (push) Successful in 1m3s
2026-06-16 10:16:23 +08:00
OoO
32b7071ab6 V10.614 部署監控頁繁中化
All checks were successful
CD Pipeline / deploy (push) Successful in 1m11s
2026-06-16 10:03:18 +08:00
OoO
239b773288 V10.613 高可見頁面繁中化
All checks were successful
CD Pipeline / deploy (push) Successful in 1m14s
2026-06-16 09:54:27 +08:00
OoO
56ebba045b V10.612 讓價格參考表優先讀外部報價層
All checks were successful
CD Pipeline / deploy (push) Successful in 1m4s
2026-06-16 09:43:49 +08:00
OoO
cac9752aac V10.611 補強作戰入口操作提示
All checks were successful
CD Pipeline / deploy (push) Successful in 1m4s
2026-06-16 09:36:57 +08:00
OoO
b7cb807683 V10.610 作戰清單優先讀外部報價層
All checks were successful
CD Pipeline / deploy (push) Successful in 1m11s
2026-06-16 09:21:40 +08:00
OoO
a3ace326c8 V10.609 自動同步外部報價資料
All checks were successful
CD Pipeline / deploy (push) Successful in 1m5s
2026-06-15 21:34:48 +08:00
OoO
df6714c3f7 V10.608 新增外部報價 CSV 預檢
All checks were successful
CD Pipeline / deploy (push) Successful in 1m7s
2026-06-15 20:39:32 +08:00
OoO
9260cc1740 V10.607 建立外部市場來源正規化層
All checks were successful
CD Pipeline / deploy (push) Successful in 1m4s
2026-06-15 16:19:03 +08:00
OoO
01cc027622 V10.606 正名 PChome 業績成長作戰系統
All checks were successful
CD Pipeline / deploy (push) Successful in 1m6s
2026-06-15 15:37:11 +08:00
OoO
4683b58f91 記錄 PChome 業績匯出自動化方案 2026-06-15 15:14:37 +08:00
OoO
55e14c0332 V10.605 修復當日業績匯入與資料庫備份
All checks were successful
CD Pipeline / deploy (push) Successful in 9m17s
2026-06-15 14:52:33 +08:00
OoO
8fa95b94a9 修復定期簡報漏產與補跑可靠性 2026-06-06 15:25:20 +08:00
OoO
d6d8777e41 V10.601 收斂 Gemini 與密鑰治理
All checks were successful
CD Pipeline / deploy (push) Successful in 1m12s
2026-06-06 14:52:46 +08:00
OoO
2efe9bd931 V10.600 收斂 ICAIM 前台標籤文案
All checks were successful
CD Pipeline / deploy (push) Successful in 1m16s
2026-06-05 16:05:31 +08:00
OoO
400133fec1 V10.599 收斂前端文案與 ICAIM 載入
All checks were successful
CD Pipeline / deploy (push) Successful in 1m42s
2026-06-05 16:01:37 +08:00
OoO
9be44d27b1 V10.597 全站響應式巡檢與載入優化
Some checks failed
CD Pipeline / deploy (push) Failing after 1m54s
2026-06-05 15:48:38 +08:00
OoO
d9a13474cb V10.594 隱藏比價追蹤內部狀態碼
All checks were successful
CD Pipeline / deploy (push) Successful in 1m8s
2026-06-05 14:28:18 +08:00
OoO
c764abc7fc V10.593 重整比價覆核工作台 UX
All checks were successful
CD Pipeline / deploy (push) Successful in 1m7s
2026-06-05 14:21:54 +08:00
OoO
93065a58e4 V10.591 拆分比價型錄覆核狀態
All checks were successful
CD Pipeline / deploy (push) Successful in 1m8s
2026-06-05 11:06:47 +08:00
OoO
bb8c29e56d V10.590 修正 PChome 副標去重與比價覆核入口
All checks were successful
CD Pipeline / deploy (push) Successful in 1m7s
2026-06-04 22:00:32 +08:00
OoO
58302c9fa7 V10.588 提升比價救援穩定性與決策覆蓋
All checks were successful
CD Pipeline / deploy (push) Successful in 1m9s
2026-06-04 21:21:40 +08:00
OoO
5347c95b97 V10.586 加速比價補抓並提升覆蓋率
All checks were successful
CD Pipeline / deploy (push) Successful in 1m7s
2026-06-04 19:31:24 +08:00
OoO
1dd4181fab V10.585 提升比價覆蓋工作台與每日業績圖表
All checks were successful
CD Pipeline / deploy (push) Successful in 1m17s
2026-06-04 19:12:34 +08:00
OoO
a1e56a2c6b V10.584 強化 PChome Nick 比對窄門
All checks were successful
CD Pipeline / deploy (push) Successful in 1m6s
2026-06-04 14:33:26 +08:00
OoO
133232e2f4 V10.583 補 Paula PChome Nick 比價對齊
All checks were successful
CD Pipeline / deploy (push) Successful in 1m7s
2026-06-04 14:13:37 +08:00
OoO
35ad29b04d V10.582 強化比價通知與身份證據
All checks were successful
CD Pipeline / deploy (push) Successful in 1m6s
2026-06-04 14:03:21 +08:00
OoO
bfb8e3c99d V10.581 接線重複單品組重評窄門
All checks were successful
CD Pipeline / deploy (push) Successful in 1m7s
2026-06-04 11:58:52 +08:00
OoO
69fa191097 V10.580 強化重複單品組安全比價 2026-06-04 11:55:25 +08:00
OoO
03d60c202f V10.579 強化高信心比價安全覆蓋
All checks were successful
CD Pipeline / deploy (push) Successful in 1m8s
2026-06-04 11:39:33 +08:00
OoO
3f528dade3 V10.578 修正 Code Review timeout 誤報
All checks were successful
CD Pipeline / deploy (push) Successful in 1m5s
2026-06-04 11:32:07 +08:00
OoO
5f7073798a V10.577 補 Code Review Ollama preflight
All checks were successful
CD Pipeline / deploy (push) Successful in 1m6s
2026-06-04 11:28:03 +08:00
OoO
3b9448b776 V10.576 修正 GCP-only Ollama retry
All checks were successful
CD Pipeline / deploy (push) Successful in 1m5s
2026-06-04 11:20:52 +08:00
OoO
58e8d5ee0f V10.575 補型錄覆核 lane 狀態 API 2026-06-04 11:19:53 +08:00
OoO
b2604a576d V10.575 拆分型錄可比覆核 lane
All checks were successful
CD Pipeline / deploy (push) Successful in 1m23s
2026-06-04 11:13:35 +08:00
OoO
facf53b925 V10.574 對齊來源治理橋接版本紀錄 2026-06-03 10:48:48 +08:00
OoO
e78b2720d9 V10.574 串接型錄可比覆核與來源治理橋接
All checks were successful
CD Pipeline / deploy (push) Successful in 1m6s
2026-06-03 10:42:41 +08:00
OoO
930ad402ff V10.572 補 PChome 決策支援覆蓋率
All checks were successful
CD Pipeline / deploy (push) Successful in 1m7s
2026-06-02 12:05:58 +08:00
OoO
6134b8e332 V10.571 強化 PChome 覆蓋率搜尋召回 2026-06-02 11:52:04 +08:00
OoO
01119c2c82 V10.570 補 PChome 身份報價證據契約 2026-06-02 11:18:52 +08:00
OoO
a32982395e V10.569 串接 Webcrumbs 比價信封摘要
All checks were successful
CD Pipeline / deploy (push) Successful in 1m8s
2026-06-02 10:56:01 +08:00
OoO
97e7e2843b V10.568 優化價格決策信封通知
All checks were successful
CD Pipeline / deploy (push) Successful in 1m6s
2026-06-02 10:47:09 +08:00
OoO
d90f96fab3 V10.567 收斂 MCP 市場洞察 fallback
All checks were successful
CD Pipeline / deploy (push) Successful in 1m6s
2026-06-02 10:09:36 +08:00
OoO
462e354a71 V10.566 新增市場情報來源治理 gate
All checks were successful
CD Pipeline / deploy (push) Successful in 1m14s
2026-06-01 22:03:15 +08:00
OoO
6cf2d23521 V10.565 補比價覆蓋率操作建議 2026-06-01 21:48:59 +08:00
OoO
3ca0f742f7 V10.563 收斂 preview 假可救候選 2026-06-01 21:43:01 +08:00
OoO
94e1967171 V10.561 補比價補強分段回饋 2026-06-01 21:26:26 +08:00
OoO
07db301c54 V10.560 串接手動比價補強流程 2026-06-01 21:22:52 +08:00
OoO
42b1c25418 V10.559 收斂 retryable 有效身份新鮮度 2026-06-01 21:17:22 +08:00
OoO
f232639c99 V10.558 補 legacy focused reason 回刷 2026-06-01 20:58:04 +08:00
OoO
7a26bfa388 V10.557 收緊 focused reason 回刷 guard 2026-06-01 15:02:16 +08:00
OoO
66f2c50964 V10.556 補 GCP-B 模型 fallback 防 111 過載 2026-06-01 14:55:13 +08:00
OoO
24597dcebb V10.555 接線 focused reason 回刷窄門 2026-06-01 14:44:57 +08:00
OoO
e820fa2e80 V10.554 接線香氛精油 focused 回刷 2026-06-01 14:34:49 +08:00
OoO
47d5c8043b V10.553 瘦身 current 比價結果查詢 2026-06-01 13:17:06 +08:00
OoO
e0ed5cc732 V10.552 收斂決策查詢新鮮度口徑 2026-06-01 13:13:01 +08:00
OoO
e68c6c22d1 V10.551 收斂未知新鮮度刷新入口 2026-06-01 13:09:15 +08:00
OoO
7cb523be18 V10.550 補安全搜尋召回詞 2026-06-01 12:42:24 +08:00
OoO
339bf68e14 V10.549 收斂比價新鮮度口徑 2026-06-01 12:34:16 +08:00
OoO
12dc452061 V10.548 接線 focused exact 舊候選回刷 2026-06-01 12:26:13 +08:00
OoO
f10d73ff83 V10.547 強化單位價覆核洞察 2026-06-01 12:19:48 +08:00
OoO
e5ecf5512e V10.546 補近門檻舊候選回刷 2026-06-01 12:09:29 +08:00
OoO
e4534c2f96 V10.545 收斂比價覆蓋率口徑 2026-06-01 12:02:22 +08:00
OoO
83b813c1b9 V10.544 收斂變體安全與 YES 工具線 2026-06-01 10:33:22 +08:00
OoO
35b9d0f0c5 V10.543 回刷 rescore focused exact 候選 2026-06-01 10:12:26 +08:00
OoO
4bc271f7ed V10.542 拆分可用比價覆蓋率口徑 2026-06-01 10:01:48 +08:00
OoO
7e057435c5 V10.541 收斂高信心 exact 覆核池 2026-06-01 09:49:56 +08:00
OoO
c0a7a55b72 V10.540 補 OPI 指彩型號精準救回 2026-06-01 09:41:36 +08:00
OoO
da546dd8d5 V10.539 補任選 catalog focused exact 防線 2026-06-01 09:23:46 +08:00
OoO
12c8c7e94d V10.538 對齊 ai_calls ollama_other provider
All checks were successful
CD Pipeline / deploy (push) Successful in 1m6s
2026-06-01 02:37:12 +08:00
OoO
6e70a6eb47 V10.537 接通 focused true_low revalidation queue
All checks were successful
CD Pipeline / deploy (push) Successful in 1m7s
2026-06-01 02:28:37 +08:00
OoO
dcdef76f06 V10.536 補高分 true_low_confidence focused exact
All checks were successful
CD Pipeline / deploy (push) Successful in 1m12s
2026-06-01 02:24:23 +08:00
OoO
5e1428c887 V10.535 優化 ElephantAlpha 價格 trigger 查詢 2026-06-01 02:24:23 +08:00
OoO
2a11ba26a7 V10.534 收緊 PChome rescore 覆核語意
All checks were successful
CD Pipeline / deploy (push) Successful in 1m8s
2026-06-01 02:14:34 +08:00
OoO
f3c37c471d V10.533 補 OpenClaw 動態定價 advisory 相容
All checks were successful
CD Pipeline / deploy (push) Successful in 1m15s
2026-06-01 02:06:22 +08:00
OoO
500cccf14d V10.532 對齊 PChome coverage 待審口徑
All checks were successful
CD Pipeline / deploy (push) Successful in 1m13s
2026-06-01 02:04:13 +08:00
OoO
d03db3c015 V10.531 補安全 exact 多件組與護唇比對
All checks were successful
CD Pipeline / deploy (push) Successful in 1m6s
2026-06-01 01:50:52 +08:00
OoO
0fed025c58 V10.530 暫停 recover-stale 主操作入口
All checks were successful
CD Pipeline / deploy (push) Successful in 1m8s
2026-06-01 01:29:22 +08:00
OoO
4557533c52 V10.529 補強 stale 救援名稱擋詞
All checks were successful
CD Pipeline / deploy (push) Successful in 1m8s
2026-06-01 01:17:32 +08:00
OoO
0304f666d4 V10.528 輕量化過期 identity 救援預覽
Some checks failed
CD Pipeline / deploy (push) Has been cancelled
2026-06-01 01:15:31 +08:00
OoO
3a045fddfc V10.527 收斂過期 identity 救援隊列
All checks were successful
CD Pipeline / deploy (push) Successful in 1m6s
2026-06-01 01:03:25 +08:00
OoO
b9b3a410ff V10.526 補過期 identity 搜尋救援入口
All checks were successful
CD Pipeline / deploy (push) Successful in 1m7s
2026-06-01 00:51:05 +08:00
OoO
3c92ebf34b V10.525 補 review-gated exact 候選重評
All checks were successful
CD Pipeline / deploy (push) Successful in 1m7s
2026-06-01 00:35:09 +08:00
OoO
98d91f2e3f V10.525 補高分舊候選窄門重評 2026-06-01 00:34:45 +08:00
OoO
87d47f171c V10.524 補 PChome 過期價格刷新入口
Some checks failed
CD Pipeline / deploy (push) Failing after 1m28s
2026-06-01 00:29:20 +08:00
OoO
915b8d061d V10.523 補安全 exact 同款比價規則
All checks were successful
CD Pipeline / deploy (push) Successful in 1m7s
2026-06-01 00:21:10 +08:00
OoO
41bd6c6e77 V10.522 補 PChome backfill coverage 狀態
Some checks failed
CD Pipeline / deploy (push) Failing after 1m5s
2026-06-01 00:16:19 +08:00
OoO
81062b624b docs: 補記過期價格刷新排序規範 2026-05-31 23:51:48 +08:00
OoO
bf2888b0fb V10.521 顯示比價 stale 新鮮度指標
All checks were successful
CD Pipeline / deploy (push) Successful in 1m7s
2026-05-31 23:49:43 +08:00
OoO
dd6b6160fe V10.520 拆分過期價格刷新與搜尋救援
All checks were successful
CD Pipeline / deploy (push) Successful in 1m11s
2026-05-31 23:41:44 +08:00
OoO
371a2b325e V10.519 對齊 Webcrumbs host data 新覆蓋口徑 2026-05-31 23:39:34 +08:00
OoO
11896c24dc V10.518 拆分比價覆蓋與價格新鮮度
All checks were successful
CD Pipeline / deploy (push) Successful in 1m9s
2026-05-31 23:16:06 +08:00
OoO
c91d20f26b V10.517 強化近門檻商品比對防線 2026-05-31 22:44:56 +08:00
OoO
ea1043ef7c V10.516 補 Webcrumbs host data 授權回歸測試
All checks were successful
CD Pipeline / deploy (push) Successful in 1m6s
2026-05-31 21:09:27 +08:00
OoO
353465d38a V10.515 收緊 Webcrumbs host data 授權
All checks were successful
CD Pipeline / deploy (push) Successful in 1m6s
2026-05-31 20:59:47 +08:00
OoO
f3a3cfe52a V10.514 新增 Webcrumbs host data API
All checks were successful
CD Pipeline / deploy (push) Successful in 1m10s
2026-05-31 20:56:14 +08:00
OoO
89d8c454bb V10.513 模組化外部工具診斷 payload
All checks were successful
CD Pipeline / deploy (push) Successful in 1m8s
2026-05-31 20:53:00 +08:00
OoO
73d2d863e5 V10.512 接上 Webcrumbs 比價 host data
All checks were successful
CD Pipeline / deploy (push) Successful in 1m8s
2026-05-31 20:49:46 +08:00
OoO
7cf0235ac7 V10.511 收斂 Webcrumbs plugin 診斷空狀態
All checks were successful
CD Pipeline / deploy (push) Successful in 1m7s
2026-05-31 20:43:02 +08:00
OoO
af0b49a819 V10.510 啟用 Webcrumbs live plugin 試點
All checks were successful
CD Pipeline / deploy (push) Successful in 1m6s
2026-05-31 20:39:08 +08:00
OoO
593e87b175 V10.509 接入 Webcrumbs 同源資產代理與 writer preflight gate
All checks were successful
CD Pipeline / deploy (push) Successful in 1m8s
2026-05-31 20:32:20 +08:00
OoO
72ded9e1e5 V10.507 接入 Webcrumbs 並收斂 writer approval gate
All checks were successful
CD Pipeline / deploy (push) Successful in 1m21s
2026-05-31 19:01:54 +08:00
OoO
b347aa44b9 V10.505 新增市場情報 writer review decision gate 2026-05-31 18:19:28 +08:00
OoO
58ac16781c V10.504 新增市場情報 writer review inventory gate 2026-05-31 17:38:38 +08:00
OoO
df7400c6cd V10.503 新增市場情報 writer review handoff gate 2026-05-31 17:07:31 +08:00
OoO
b7838b382f V10.502 修正 AiderHeal 自動修復診斷 2026-05-31 16:49:45 +08:00
OoO
46aa89ddfa V10.501 新增市場情報 writer post-closeout inventory review gate 2026-05-31 16:22:54 +08:00
OoO
2e8f57dfbe V10.500 add market intel queue writer run closeout review gate 2026-05-31 15:52:56 +08:00
OoO
8f10930cca V10.499 add market intel queue writer run receipt review gate 2026-05-31 15:25:05 +08:00
OoO
64b4ec39ec V10.498 add market intel queue writer run readiness gate 2026-05-31 14:44:43 +08:00
OoO
9843843fbb V10.497 add market intel queue writer run package review gate 2026-05-31 14:23:28 +08:00
OoO
b109bbf3c4 V10.496 add market intel queue writer cli review gate 2026-05-31 13:52:05 +08:00
OoO
d1a08b0b37 V10.495 add market intel queue writer preflight gate 2026-05-31 13:35:52 +08:00
OoO
cef27c77df V10.494 add market intel candidate queue review gate 2026-05-31 13:08:53 +08:00
OoO
c196a0e228 V10.493 add market intel candidate handoff review gate 2026-05-31 12:52:35 +08:00
OoO
06e196a282 收緊 PChome 近門檻自動回刷隊列 2026-05-31 12:47:04 +08:00
OoO
d98f24e8eb V10.491 add market intel fetch parser review gate 2026-05-31 12:29:20 +08:00
OoO
291cdf019f 補齊 OpenClaw 市場策略 action 相容 2026-05-31 12:26:17 +08:00
OoO
998e0da9b4 記錄 V10.489 正式部署驗證 2026-05-29 11:32:39 +08:00
OoO
c1b2fa82f5 V10.489 strengthen PChome manual review matching 2026-05-29 11:24:27 +08:00
OoO
81701e85f4 V10.488 add market intel MCP fetch receipt gate
All checks were successful
CD Pipeline / deploy (push) Successful in 1m12s
2026-05-29 11:17:37 +08:00
OoO
afa91755c1 補強 PChome near-threshold 風險邊界
All checks were successful
CD Pipeline / deploy (push) Successful in 1m11s
2026-05-29 10:32:54 +08:00
OoO
e4de72d7d7 拆分 PChome manual gate 與型錄風險
All checks were successful
CD Pipeline / deploy (push) Successful in 1m3s
2026-05-25 23:56:35 +08:00
OoO
f2aa81815e 收斂 PChome gate pass 變體風險
All checks were successful
CD Pipeline / deploy (push) Successful in 1m5s
2026-05-25 23:08:31 +08:00
OoO
64a39a89b3 強化 PChome exact variant-safe 回收
All checks were successful
CD Pipeline / deploy (push) Successful in 1m5s
2026-05-25 21:56:32 +08:00
OoO
e6b48cefa8 強化 PChome accepted queue 變體防線
All checks were successful
CD Pipeline / deploy (push) Successful in 1m4s
2026-05-25 21:35:41 +08:00
OoO
50daad84a7 強化 PChome 變體錯配防線
All checks were successful
CD Pipeline / deploy (push) Successful in 1m5s
2026-05-25 20:53:47 +08:00
OoO
630d4c73bc 強化 PChome 高分錯配與變體審核
All checks were successful
CD Pipeline / deploy (push) Successful in 1m9s
2026-05-25 20:14:25 +08:00
OoO
6c5854bb5f 補強 PChome 比對商業條件防線
All checks were successful
CD Pipeline / deploy (push) Successful in 1m5s
2026-05-25 19:00:07 +08:00
OoO
bd33f7ff60 強化 PChome rescore 漏掃與錯配防線
All checks were successful
CD Pipeline / deploy (push) Successful in 1m4s
2026-05-25 16:05:08 +08:00
OoO
dab782cc6d 優化 PChome 近門檻商品比對回收
All checks were successful
CD Pipeline / deploy (push) Successful in 1m4s
2026-05-25 15:20:36 +08:00
OoO
a00f34ce87 加入 Ollama GCP failover 診斷與 unhealthy skip
All checks were successful
CD Pipeline / deploy (push) Successful in 1m5s
2026-05-25 14:16:51 +08:00
OoO
44ef5a70a1 校準 GCP-B embedding timeout
All checks were successful
CD Pipeline / deploy (push) Successful in 1m6s
2026-05-25 13:43:10 +08:00
OoO
e3dadc28db 強化 Ollama host health runtime 探針 2026-05-25 12:53:35 +08:00
OoO
aad26ea87c 記錄 V10.469 embedding 降噪部署 2026-05-25 12:39:35 +08:00
OoO
ac5539a8ef 調整背景 embedding 熔斷告警語意
All checks were successful
CD Pipeline / deploy (push) Successful in 1m5s
2026-05-25 12:35:56 +08:00
OoO
35f5f87618 記錄 V10.468 Ollama 部署 smoke 2026-05-25 12:31:24 +08:00
OoO
0ade55469e 穩定 Ollama embedding GCP 失敗熔斷
All checks were successful
CD Pipeline / deploy (push) Successful in 1m5s
2026-05-25 12:28:44 +08:00
OoO
e1c9499c1c 記錄 V10.467 比對 pilot 部署驗證 2026-05-25 12:08:49 +08:00
OoO
5c0ff7f8cf 補強 PChome 精準同款 total price 通道 2026-05-25 12:05:29 +08:00
OoO
7e29c00eb8 修正 PChome rescore 重複入隊判斷 2026-05-25 12:00:12 +08:00
OoO
61816c90e8 Record V10.465 embedding deployment verification 2026-05-25 10:04:52 +08:00
OoO
3fd349c830 Keep embedding retry on GCP when 111 fallback disabled
All checks were successful
CD Pipeline / deploy (push) Successful in 1m5s
2026-05-25 09:59:00 +08:00
OoO
f3a199434f Record V10.464 rescore pilot verification 2026-05-25 08:39:35 +08:00
OoO
da7bc88b5e Add SKU-scoped PChome rescore pilot
All checks were successful
CD Pipeline / deploy (push) Successful in 1m4s
2026-05-25 08:33:05 +08:00
OoO
b877805a4c Normalize DRWU brand alias for PChome matching
All checks were successful
CD Pipeline / deploy (push) Successful in 1m20s
2026-05-25 08:26:50 +08:00
OoO
19d960a79d Record V10.462 deployment verification 2026-05-25 08:18:05 +08:00
OoO
8a75d34276 Clarify PChome backfill wording
All checks were successful
CD Pipeline / deploy (push) Successful in 1m6s
2026-05-25 08:15:39 +08:00
OoO
4a43a3075a Record V10.461 deployment verification 2026-05-25 08:12:50 +08:00
OoO
92fac19b87 Record V10.461 dashboard wording task 2026-05-25 08:11:30 +08:00
OoO
aa8fdd109f Document PChome unsearched state wording 2026-05-25 08:11:12 +08:00
OoO
c3130b28dd Clarify unsearched PChome dashboard state 2026-05-25 07:18:44 +08:00
OoO
4f4ee82277 Record V10.460 deployment verification 2026-05-24 23:59:39 +08:00
OoO
238c626bcb Sync EA envelope inventory count 2026-05-24 23:57:53 +08:00
OoO
0f7ad3e036 Tighten chart guards and EA envelopes
All checks were successful
CD Pipeline / deploy (push) Successful in 1m4s
2026-05-24 23:56:17 +08:00
OoO
916ddc010b Guard daily sales import date cast 2026-05-24 23:45:09 +08:00
OoO
7b784d6819 Record V10.459 deployment verification 2026-05-24 23:43:05 +08:00
OoO
b297491efe Explain protected PChome match conflicts
All checks were successful
CD Pipeline / deploy (push) Successful in 1m6s
2026-05-24 23:39:48 +08:00
OoO
bc48926cc5 Record V10.458 deployment verification 2026-05-24 23:33:37 +08:00
OoO
2381af5ee0 Record V10.458 deployment 2026-05-24 23:28:08 +08:00
OoO
c0a06e1798 Share review envelopes with OpenClaw and PPT 2026-05-24 23:25:51 +08:00
OoO
05d6eadf1b Record V10.457 deployment 2026-05-24 23:16:37 +08:00
OoO
b0a267823a Surface review decision envelopes in dashboard export 2026-05-24 23:14:46 +08:00
OoO
98cd401f88 Record V10.456 deployment 2026-05-24 23:05:20 +08:00
OoO
2ca3559df2 Attach decision envelopes to review queue 2026-05-24 23:03:11 +08:00
OoO
a4aa796114 Record V10.455 deployment 2026-05-24 22:52:47 +08:00
OoO
9a96e9500b Render price decision envelopes directly 2026-05-24 22:49:46 +08:00
OoO
ac575a6499 Clarify V10.454 rescore guardrails 2026-05-24 22:37:03 +08:00
OoO
a726f012d5 Clarify V10.454 rescore guardrails 2026-05-24 22:33:01 +08:00
OoO
04acb3079d Exclude variant review from rescore accepted gate 2026-05-24 22:31:02 +08:00
OoO
97e33bf1e0 Guard PChome feeder auto price writes 2026-05-24 22:30:14 +08:00
OoO
90eaf82d02 Record V10.453 deployment 2026-05-24 22:18:34 +08:00
OoO
714a5716db Align PChome rescore audit and matcher safeguards 2026-05-24 22:14:42 +08:00
OoO
4238d0f87b Correct V10.451 deployment note 2026-05-24 21:38:16 +08:00
OoO
d446ba0f2f Record V10.451 deployment 2026-05-24 21:32:53 +08:00
OoO
8340df8cb7 Split PChome review low-score buckets 2026-05-24 21:28:27 +08:00
OoO
3bbd4c15ba Record deploy channel outage 2026-05-24 21:20:50 +08:00
OoO
dcabebbcf2 Expose PChome rescore review metrics 2026-05-24 21:12:27 +08:00
OoO
0fff09a15c Keep exact counts for filtered PChome reviews 2026-05-24 21:03:02 +08:00
OoO
0709392d9d Skip exact count for full PChome review page 2026-05-24 19:00:13 +08:00
OoO
82b5616921 Start PChome review queue from latest attempts
All checks were successful
CD Pipeline / deploy (push) Successful in 1m5s
2026-05-24 18:52:57 +08:00
OoO
f950c28169 Avoid heavy overview SQL on PChome review page
All checks were successful
CD Pipeline / deploy (push) Successful in 1m20s
2026-05-24 18:47:25 +08:00
OoO
bfd5b213b2 Add lightweight PChome review dashboard path
All checks were successful
CD Pipeline / deploy (push) Successful in 1m4s
2026-05-24 18:41:01 +08:00
OoO
5d4927c119 Optimize PChome review queue paging
Some checks failed
CD Pipeline / deploy (push) Has been cancelled
2026-05-24 18:31:26 +08:00
OoO
5aa2412dee Route rescore matches to manual review 2026-05-24 18:20:36 +08:00
OoO
710f7216d0 Silence disabled GitLab CI monitor
All checks were successful
CD Pipeline / deploy (push) Successful in 1m8s
2026-05-24 18:12:58 +08:00
OoO
9fd8ac2886 Document V10.441 execution queue closeout 2026-05-24 18:02:50 +08:00
OoO
f6f9bf574c Add competitor match rescore audit 2026-05-24 18:00:41 +08:00
OoO
48c5db3b85 Promote Mustela lotion identity anchor 2026-05-24 17:46:30 +08:00
OoO
c5db3eb0da Keep external BI links inside momo pro
Some checks failed
CD Pipeline / deploy (push) Failing after 10m17s
2026-05-24 17:43:25 +08:00
OoO
bfc5dac624 Tighten PPT audit regeneration workflow 2026-05-24 17:34:18 +08:00
OoO
ef9c2272b9 V10.437 harden sales chart rendering
All checks were successful
CD Pipeline / deploy (push) Successful in 1m6s
2026-05-24 17:15:21 +08:00
OoO
1eef91ec7a Fix daily sales snapshot date casts 2026-05-24 17:09:22 +08:00
OoO
d522c07b39 V10.435 align dashboard match diagnostics 2026-05-24 17:03:01 +08:00
OoO
105178e50b V10.434 complete PChome review closure controls 2026-05-24 16:59:18 +08:00
OoO
a1df2bc8d5 V10.433 improve competitor review diagnostics 2026-05-24 16:51:19 +08:00
OoO
051c654713 V10.432 tighten marketplace near-threshold matching 2026-05-24 16:41:14 +08:00
OoO
d650b10797 V10.431 make event ignore callbacks byte safe 2026-05-24 16:34:17 +08:00
OoO
1f2e8b1e84 V10.430 preserve Nemotron decision callback IDs 2026-05-24 16:21:04 +08:00
OoO
b389a50e07 V10.429 complete runtime governance docs
All checks were successful
CD Pipeline / deploy (push) Successful in 1m3s
2026-05-24 16:15:23 +08:00
OoO
0251835999 V10.428 add Nemotron price decision envelopes 2026-05-24 16:03:56 +08:00
OoO
5ae28083d9 V10.427 add 111 Ollama circuit breaker 2026-05-24 15:55:12 +08:00
OoO
1717dad3d7 V10.426 deduplicate 111 proxy reject logs 2026-05-24 15:50:39 +08:00
OoO
0208c014d2 V10.425 add 111 Ollama usage guard
All checks were successful
CD Pipeline / deploy (push) Successful in 1m6s
2026-05-24 15:44:02 +08:00
OoO
868d75f972 V10.424 stabilize 111 proxy launch agent install
Some checks failed
CD Pipeline / deploy (push) Has been cancelled
2026-05-24 15:41:07 +08:00
OoO
1487f7fb10 V10.423 add agent decision envelope alerts
Some checks failed
CD Pipeline / deploy (push) Has been cancelled
2026-05-24 15:38:52 +08:00
OoO
6d22d4920e V10.422 persist 111 Ollama proxy launch agent 2026-05-24 15:38:52 +08:00
OoO
bf88fcd48e V10.421 guard marketplace line mismatches 2026-05-24 15:29:50 +08:00
OoO
2f1ba21352 V10.420 guard 111 Ollama LAN access 2026-05-24 15:27:11 +08:00
OoO
0d81839447 docs: record V10.419 production pilot 2026-05-24 15:15:21 +08:00
OoO
0406a62611 V10.419 guard Dr.Hsieh serum line matching 2026-05-24 15:12:45 +08:00
OoO
7090f08dba V10.418 skip 111 in embedding consistency checks 2026-05-24 15:03:10 +08:00
OoO
353e565e52 V10.417 protect embedding fallback routing
All checks were successful
CD Pipeline / deploy (push) Successful in 1m4s
2026-05-24 14:53:43 +08:00
OoO
30e30ac7b6 docs: record V10.416 production pilot 2026-05-24 14:47:12 +08:00
OoO
4f64934818 V10.416 harden marketplace variant vetoes
All checks were successful
CD Pipeline / deploy (push) Successful in 1m6s
2026-05-24 14:42:29 +08:00
OoO
ae0f1e5a81 docs: record V10.415 production pilot 2026-05-24 14:35:18 +08:00
OoO
b73dc6df3f V10.415 protect Hermes fallback routing
All checks were successful
CD Pipeline / deploy (push) Successful in 1m5s
2026-05-24 14:25:22 +08:00
OoO
1b94177828 V10.414 add market intel MCP fetch run readiness gate
All checks were successful
CD Pipeline / deploy (push) Successful in 1m24s
2026-05-24 14:16:55 +08:00
OoO
6ac412716a V10.413 protect code review fallback host
All checks were successful
CD Pipeline / deploy (push) Successful in 1m6s
2026-05-24 14:05:59 +08:00
OoO
74e19400bd V10.412 add market intel MCP fetch run package gate
Some checks failed
CD Pipeline / deploy (push) Has been cancelled
2026-05-24 14:00:59 +08:00
OoO
8d9984dc04 V10.411 rescue focused marketplace matches
All checks were successful
CD Pipeline / deploy (push) Successful in 1m3s
2026-05-24 13:54:59 +08:00
OoO
5ea556d406 V10.410 tune code review ollama timeouts
All checks were successful
CD Pipeline / deploy (push) Successful in 1m4s
2026-05-24 13:42:54 +08:00
OoO
469a5845e8 V10.408 record OPI pilot validation 2026-05-24 13:38:44 +08:00
OoO
bc8afd026c V10.409 add market intel MCP fetch target review gate
All checks were successful
CD Pipeline / deploy (push) Successful in 1m3s
2026-05-24 13:36:53 +08:00
OoO
65d38d4632 V10.407 shorten ai runner residency
All checks were successful
CD Pipeline / deploy (push) Successful in 1m34s
2026-05-24 13:32:35 +08:00
OoO
717231167f V10.406 shorten code review ollama keepalive
All checks were successful
CD Pipeline / deploy (push) Successful in 1m6s
2026-05-24 13:24:59 +08:00
OoO
768127ac52 V10.405 add market intel MCP manual fetch handoff gate
All checks were successful
CD Pipeline / deploy (push) Successful in 1m6s
2026-05-24 13:15:14 +08:00
OoO
1272c01ec6 V10.404 gate Hermes direct price alerts
All checks were successful
CD Pipeline / deploy (push) Successful in 1m6s
2026-05-24 13:13:00 +08:00
OoO
b2dbf98c3b V10.403 widen retryable PChome revalidation
All checks were successful
CD Pipeline / deploy (push) Successful in 1m5s
2026-05-24 12:54:44 +08:00
OoO
56f787351a V10.402 tighten catalog variant review matches
All checks were successful
CD Pipeline / deploy (push) Successful in 1m3s
2026-05-24 12:49:45 +08:00
OoO
d66d29c3ee V10.401 tighten focused identity boundaries
All checks were successful
CD Pipeline / deploy (push) Successful in 1m3s
2026-05-24 12:30:18 +08:00
OoO
bbf21b81af V10.400 normalize cushion refill pack matches
All checks were successful
CD Pipeline / deploy (push) Successful in 1m4s
2026-05-24 12:27:20 +08:00
OoO
8b4bcdf277 V10.399 demote named variant catalog alerts
All checks were successful
CD Pipeline / deploy (push) Successful in 1m6s
2026-05-24 12:19:03 +08:00
OoO
4622be3441 V10.398 recover true low confidence matches
All checks were successful
CD Pipeline / deploy (push) Successful in 1m5s
2026-05-24 12:05:40 +08:00
OoO
8cc197aba2 V10.397 reduce competitor audit false negatives
All checks were successful
CD Pipeline / deploy (push) Successful in 1m2s
2026-05-24 11:43:13 +08:00
OoO
01c888c565 V10.396 add offline competitor identity audit
All checks were successful
CD Pipeline / deploy (push) Successful in 1m6s
2026-05-24 11:09:02 +08:00
OoO
68f9e051f4 V10.394 guard catalog option and starter set matches
Some checks failed
CD Pipeline / deploy (push) Has been cancelled
2026-05-24 11:01:42 +08:00
OoO
af48452fd6 V10.393 refine bundle plus matching
All checks were successful
CD Pipeline / deploy (push) Successful in 1m4s
2026-05-24 10:55:15 +08:00
OoO
4da4a07a78 V10.392 guard multi-component bundle matches
All checks were successful
CD Pipeline / deploy (push) Successful in 1m3s
2026-05-24 10:40:35 +08:00
OoO
6d4b188787 V10.391 handle catalog variant listings
All checks were successful
CD Pipeline / deploy (push) Successful in 1m7s
2026-05-24 10:33:02 +08:00
OoO
0538c8d5f6 Document V10.390 matcher release
Some checks failed
CD Pipeline / deploy (push) Has been cancelled
2026-05-24 10:28:42 +08:00
OoO
d2dea022ea 修正 PChome 近門檻商品比對規則 2026-05-24 10:28:42 +08:00
OoO
4ae3a39970 V10.388 guard serum formulation matches
All checks were successful
CD Pipeline / deploy (push) Successful in 1m5s
2026-05-21 20:36:24 +08:00
OoO
b7b12829f9 Document jump host SSH key repair 2026-05-21 20:31:25 +08:00
OoO
b6de73a4a1 V10.387 improve EA price alert evidence
All checks were successful
CD Pipeline / deploy (push) Successful in 1m3s
2026-05-21 20:25:40 +08:00
OoO
2ae377dadf V10.386 harden Gemini compose defaults
Some checks failed
CD Pipeline / deploy (push) Has been cancelled
2026-05-21 20:14:36 +08:00
OoO
63470b69d3 補強 Lactacyd 與 MAQuillAGE 同款比對
All checks were successful
CD Pipeline / deploy (push) Successful in 1m25s
2026-05-21 20:07:44 +08:00
OoO
05643de83a 補強 Karadium 眼影棒同款比對
All checks were successful
CD Pipeline / deploy (push) Successful in 1m4s
2026-05-21 19:04:10 +08:00
OoO
5a5f268358 強化 EA JSON fallback 與 EDM cache 自癒
Some checks failed
CD Pipeline / deploy (push) Has been cancelled
2026-05-21 18:59:16 +08:00
OoO
31f88898c2 放行唇膏同款寬價差比對
All checks were successful
CD Pipeline / deploy (push) Successful in 1m7s
2026-05-21 18:49:00 +08:00
OoO
0cea70890a 導入 browse.sh 比價診斷計畫
All checks were successful
CD Pipeline / deploy (push) Successful in 1m21s
2026-05-21 18:40:49 +08:00
OoO
106c1935f4 收緊 111 Ollama fallback 資源上限
Some checks failed
CD Pipeline / deploy (push) Failing after 11m7s
2026-05-21 18:13:50 +08:00
OoO
9ada32477c [V10.379] add market intel MCP runtime promotion gate
All checks were successful
CD Pipeline / deploy (push) Successful in 1m6s
2026-05-21 16:29:21 +08:00
OoO
c522bfc5f6 移除 AI route 測試檔尾空白 2026-05-21 16:25:48 +08:00
OoO
c7fdd57156 修正 AI 推薦頁 Gemini 主路徑顯示
All checks were successful
CD Pipeline / deploy (push) Successful in 1m4s
2026-05-21 16:25:02 +08:00
OoO
e3da4ffbb3 阻止 Gemini 成為推薦主路徑
All checks were successful
CD Pipeline / deploy (push) Successful in 1m6s
2026-05-21 16:18:35 +08:00
OoO
de10712586 補強 Recipe Box 同款防曬比對
All checks were successful
CD Pipeline / deploy (push) Successful in 1m3s
2026-05-21 16:09:01 +08:00
OoO
5e2bdd5b77 停用過期活動爬蟲排程
All checks were successful
CD Pipeline / deploy (push) Successful in 1m16s
2026-05-21 16:02:58 +08:00
OoO
3ec5fa9cb5 略過失效 EDM 活動頁告警
All checks were successful
CD Pipeline / deploy (push) Successful in 1m9s
2026-05-21 15:47:40 +08:00
OoO
690cafb5a1 整合同款名稱漂移比對
All checks were successful
CD Pipeline / deploy (push) Successful in 1m5s
2026-05-21 15:39:56 +08:00
OoO
4174c90ab0 修正 smoke fallback 與 EventRouter 回放
All checks were successful
CD Pipeline / deploy (push) Successful in 1m8s
2026-05-21 15:32:23 +08:00
OoO
52790f3f6d 放行品牌缺失的強錨點同款
All checks were successful
CD Pipeline / deploy (push) Successful in 1m19s
2026-05-21 15:18:48 +08:00
OoO
1f0d37a1fe 新增 Gemini 出站 smoke sentinel 2026-05-21 15:18:48 +08:00
OoO
1c4fcae5ca 補 Gemini 出站守門測試與同款價差放行
All checks were successful
CD Pipeline / deploy (push) Successful in 1m17s
2026-05-21 15:10:43 +08:00
OoO
1bdb0f2bd8 強化比價搜尋同款錨點
All checks were successful
CD Pipeline / deploy (push) Successful in 1m3s
2026-05-21 14:45:32 +08:00
OoO
c016200bf4 硬封鎖 Gemini API 預設出站 2026-05-21 14:45:32 +08:00
OoO
60028cdbd3 [V10.366] add market intel MCP runtime smoke receipt
All checks were successful
CD Pipeline / deploy (push) Successful in 1m4s
2026-05-21 14:14:38 +08:00
OoO
78b6f156ba 強化商品比價身份分級與告警路由
All checks were successful
CD Pipeline / deploy (push) Successful in 1m9s
2026-05-21 14:04:06 +08:00
OoO
c329d96dff 限制 111 fallback context 大小
All checks were successful
CD Pipeline / deploy (push) Successful in 1m10s
2026-05-21 12:44:33 +08:00
OoO
8e4d7d306e 強化 Dashing Diva 美甲片同款比對
All checks were successful
CD Pipeline / deploy (push) Successful in 1m3s
2026-05-21 12:39:23 +08:00
OoO
00a808518e 將 111 Ollama fallback 收斂到輕量模型 2026-05-21 12:39:23 +08:00
OoO
d6ae216c8c 限制 111 Ollama fallback 資源占用
All checks were successful
CD Pipeline / deploy (push) Successful in 1m11s
2026-05-21 12:24:49 +08:00
OoO
e57793829c [V10.360] 關閉預設瀏覽器 smoke 並優化 PChome 熱路徑
All checks were successful
CD Pipeline / deploy (push) Successful in 1m5s
2026-05-21 12:07:25 +08:00
OoO
fb5a4435d7 [V10.359] 修正 merge commit code review trigger 2026-05-21 12:02:26 +08:00
OoO
e67c926ac9 Merge remote-tracking branch 'origin/main'
# Conflicts:
#	TODO_NEXT_STEPS.txt
#	config.py
#	docs/memory/history_logs.md
2026-05-21 11:59:52 +08:00
OoO
d5b41ec11b [V10.359] 導入 browse.sh 診斷與色號防錯配 2026-05-21 11:57:18 +08:00
OoO
2efec5fb15 [V10.358] 優化身份搜尋詞召回品質 2026-05-21 11:46:12 +08:00
OoO
f4ec50cd30 [V10.358] add market intel MCP activation evidence review
All checks were successful
CD Pipeline / deploy (push) Successful in 1m7s
2026-05-21 11:31:28 +08:00
OoO
958a6d9829 [V10.357] 補強妝前乳與素顏霜身份搜尋 2026-05-21 11:28:13 +08:00
OoO
8bffd0307d [V10.357] add market intel MCP completion audit
All checks were successful
CD Pipeline / deploy (push) Successful in 1m3s
2026-05-21 11:16:10 +08:00
OoO
73ec78e8ab [V10.356] add market intel catalog record final closeout gate
All checks were successful
CD Pipeline / deploy (push) Successful in 1m29s
2026-05-21 10:05:59 +08:00
OoO
e57ad01988 [V10.356] prioritize Lactacyd private wash identity 2026-05-21 10:00:55 +08:00
OoO
88101cf5d0 [V10.355] rescue near-threshold identity cohorts 2026-05-21 09:21:46 +08:00
OoO
b272abccca [V10.355] add market intel catalog record archive summary gate
All checks were successful
CD Pipeline / deploy (push) Successful in 1m5s
2026-05-21 09:19:54 +08:00
OoO
a4fcf3d3c1 [V10.354] add market intel catalog record archive gate
All checks were successful
CD Pipeline / deploy (push) Successful in 1m7s
2026-05-21 08:57:00 +08:00
OoO
1f7d8cfaf7 [V10.353] add market intel catalog record closeout gate
All checks were successful
CD Pipeline / deploy (push) Successful in 1m6s
2026-05-20 21:02:01 +08:00
OoO
09951b02ed [V10.352] promote exact anchor core-line matches 2026-05-20 20:51:50 +08:00
OoO
7441c7751b [V10.351] rescue cosmetics and aroma identity matches
All checks were successful
CD Pipeline / deploy (push) Successful in 1m5s
2026-05-20 20:42:00 +08:00
OoO
5d38735548 [V10.351] recover private care identity candidates 2026-05-20 20:34:02 +08:00
OoO
d030e4cf22 [V10.350] add retryable identity recovery loop 2026-05-20 20:24:40 +08:00
OoO
cf4d8aedea 新增市場情報 report catalog record run receipt gate
All checks were successful
CD Pipeline / deploy (push) Successful in 1m2s
2026-05-20 20:17:33 +08:00
OoO
a46396ca7f [V10.350] 關閉 Gemini 預設備援出站
All checks were successful
CD Pipeline / deploy (push) Successful in 1m6s
2026-05-20 20:10:21 +08:00
OoO
30951af04c [V10.349] tighten marketplace identity rescue logic 2026-05-20 20:09:19 +08:00
OoO
1bb8900f26 新增市場情報 report catalog record run readiness gate
All checks were successful
CD Pipeline / deploy (push) Successful in 1m5s
2026-05-20 19:58:02 +08:00
OoO
e506251194 新增市場情報 report catalog record run package gate
All checks were successful
CD Pipeline / deploy (push) Successful in 1m4s
2026-05-20 19:36:42 +08:00
OoO
8edd8a8604 [V10.346] 補強 PChome identity anchor scorer 2026-05-20 19:34:21 +08:00
OoO
67cd35e2de [V10.345] 收斂 PChome 搜尋詞特定品線
All checks were successful
CD Pipeline / deploy (push) Successful in 1m34s
2026-05-20 16:28:59 +08:00
OoO
e7ab333c58 新增市場情報 report catalog record write gate
All checks were successful
CD Pipeline / deploy (push) Successful in 1m14s
2026-05-20 16:22:51 +08:00
OoO
193b6e53c5 [V10.343] 強化 PChome 商品搜尋召回
All checks were successful
CD Pipeline / deploy (push) Successful in 1m5s
2026-05-20 16:21:19 +08:00
OoO
48e46e35c0 [V10.342] 收斂 PChome 低相似狀態語意
All checks were successful
CD Pipeline / deploy (push) Successful in 1m5s
2026-05-20 16:00:39 +08:00
OoO
760c9c0a5e [V10.341] 補強 PChome exact spec 近門檻比對
All checks were successful
CD Pipeline / deploy (push) Successful in 1m5s
2026-05-20 15:53:27 +08:00
OoO
506fed4ba3 新增市場情報 report catalog index gate
All checks were successful
CD Pipeline / deploy (push) Successful in 1m4s
2026-05-20 15:25:02 +08:00
OoO
2cc08684ec 記錄市場情報 report catalog handoff gate 2026-05-20 15:08:01 +08:00
OoO
43f340c080 [V10.338] 修正 PChome 重評 selector 收斂條件
All checks were successful
CD Pipeline / deploy (push) Successful in 1m6s
2026-05-20 15:05:25 +08:00
OoO
3f070a668b [V10.337] 兼容 PChome 商品 API list 回應
All checks were successful
CD Pipeline / deploy (push) Successful in 1m6s
2026-05-20 15:00:22 +08:00
OoO
255140224b [V10.336] 避免 PChome 低信心重評空轉
All checks were successful
CD Pipeline / deploy (push) Successful in 1m5s
2026-05-20 14:55:32 +08:00
OoO
c0ec430587 新增市場情報 report archive summary gate
All checks were successful
CD Pipeline / deploy (push) Successful in 1m13s
2026-05-20 14:48:11 +08:00
OoO
b636303481 [V10.334] 強化 PChome 比價重評與補抓可觀測性
All checks were successful
CD Pipeline / deploy (push) Successful in 1m5s
2026-05-20 14:45:41 +08:00
OoO
9c45a87723 新增市場情報 report archive gate
All checks were successful
CD Pipeline / deploy (push) Successful in 1m3s
2026-05-20 14:24:12 +08:00
OoO
396a51dd7f 新增市場情報 report closeout gate
All checks were successful
CD Pipeline / deploy (push) Successful in 1m7s
2026-05-20 14:08:05 +08:00
OoO
0facbcd8cf [V10.331] 補強多組件商品比價同款判斷
All checks were successful
CD Pipeline / deploy (push) Successful in 1m4s
2026-05-20 13:51:19 +08:00
OoO
3f2830dab5 新增市場情報 report run receipt gate
All checks were successful
CD Pipeline / deploy (push) Successful in 1m5s
2026-05-20 13:48:12 +08:00
OoO
b68125ca26 [V10.329] 延長成長分析穩定快取
All checks were successful
CD Pipeline / deploy (push) Successful in 1m5s
2026-05-20 13:32:57 +08:00
OoO
2c47a79f05 [V10.328] 強化 PChome 比價診斷與狀態分流
All checks were successful
CD Pipeline / deploy (push) Successful in 1m7s
2026-05-20 13:24:38 +08:00
OoO
875810620f [V10.327] 補 OpenClaw 備援可觀測性
All checks were successful
CD Pipeline / deploy (push) Successful in 1m28s
2026-05-20 13:00:39 +08:00
OoO
e4f3c8fc5e 新增市場情報 Telegram dispatch report run readiness gate
All checks were successful
CD Pipeline / deploy (push) Successful in 1m6s
2026-05-20 12:58:21 +08:00
OoO
3cfc82925e [V10.325] 收斂 Gemini 為 Ollama 備援
Some checks failed
CD Pipeline / deploy (push) Has been cancelled
2026-05-20 12:54:49 +08:00
OoO
6f454821a7 新增市場情報 Telegram dispatch report run package gate
All checks were successful
CD Pipeline / deploy (push) Successful in 1m4s
2026-05-20 12:42:39 +08:00
OoO
a4590db8ba [V10.323] 明確標示 seed writer API token 邊界
All checks were successful
CD Pipeline / deploy (push) Successful in 1m3s
2026-05-20 12:37:31 +08:00
OoO
4d62731730 [V10.322] 修正 Telegram 決策審核推播入口
Some checks failed
CD Pipeline / deploy (push) Has been cancelled
2026-05-20 12:35:12 +08:00
OoO
854e13201f [V10.321] 修正 Telegram HTML br 發送格式
All checks were successful
CD Pipeline / deploy (push) Successful in 1m6s
2026-05-20 12:19:45 +08:00
OoO
ca27f2e4eb 新增市場情報 Telegram dispatch report input gate
All checks were successful
CD Pipeline / deploy (push) Successful in 1m5s
2026-05-20 12:16:22 +08:00
OoO
7fa5dc72bf [V10.319] 更新市場情報 archive summary 文件索引
All checks were successful
CD Pipeline / deploy (push) Successful in 1m4s
2026-05-20 12:06:20 +08:00
OoO
e8e4e0f94f 新增市場情報 AI summary Telegram dispatch archive summary
All checks were successful
CD Pipeline / deploy (push) Successful in 1m6s
2026-05-20 12:01:45 +08:00
OoO
8d791ef50b [V10.318] 收緊 EA HITL 告警證據與排版治理
All checks were successful
CD Pipeline / deploy (push) Successful in 1m23s
2026-05-20 11:47:06 +08:00
OoO
a1818da1f3 修正 PChome 覆蓋率活躍商品分母
All checks were successful
CD Pipeline / deploy (push) Successful in 1m21s
2026-05-20 11:42:35 +08:00
OoO
6bf05ec2f1 新增市場情報 AI summary Telegram dispatch archive
All checks were successful
CD Pipeline / deploy (push) Successful in 1m22s
2026-05-20 11:40:13 +08:00
OoO
c2528c1339 修正競品歷史報表取價來源
All checks were successful
CD Pipeline / deploy (push) Successful in 1m13s
2026-05-20 11:32:40 +08:00
OoO
44b8075506 擴大 PChome 候選池與搜尋韌性
All checks were successful
CD Pipeline / deploy (push) Successful in 1m7s
2026-05-20 11:18:18 +08:00
OoO
38085d4cec 新增市場情報 AI summary Telegram dispatch closeout
All checks were successful
CD Pipeline / deploy (push) Successful in 1m8s
2026-05-20 11:13:56 +08:00
OoO
93f1a558a5 強化 PChome 商品身份比對防錯配
All checks were successful
CD Pipeline / deploy (push) Successful in 1m4s
2026-05-20 11:07:05 +08:00
OoO
f7772cc465 統一競品價差方向語意
All checks were successful
CD Pipeline / deploy (push) Successful in 1m7s
2026-05-20 10:47:20 +08:00
OoO
5b9f712abe 強化 PChome 覆核與候選決策閉環
All checks were successful
CD Pipeline / deploy (push) Successful in 1m5s
2026-05-20 10:41:29 +08:00
OoO
190695e546 新增市場情報 AI summary Telegram dispatch receipt review
All checks were successful
CD Pipeline / deploy (push) Successful in 1m6s
2026-05-20 10:33:03 +08:00
OoO
bd47115e27 修正 PChome 人工覆核狀態顯示
All checks were successful
CD Pipeline / deploy (push) Successful in 1m4s
2026-05-20 10:26:26 +08:00
OoO
296269bd43 串接 PChome 人工覆核成效指標
All checks were successful
CD Pipeline / deploy (push) Successful in 1m6s
2026-05-20 10:16:44 +08:00
OoO
8c3ca03f92 新增市場情報 AI summary Telegram dispatch run readiness
All checks were successful
CD Pipeline / deploy (push) Successful in 1m5s
2026-05-20 10:15:13 +08:00
OoO
45e1aad308 讓 PChome feeder 採納人工覆核回饋
All checks were successful
CD Pipeline / deploy (push) Successful in 1m8s
2026-05-20 10:06:46 +08:00
OoO
756b01af66 補齊 PChome 比價人工覆核閉環
All checks were successful
CD Pipeline / deploy (push) Successful in 1m7s
2026-05-20 10:00:58 +08:00
OoO
50af4be9a8 新增市場情報 AI summary Telegram dispatch run package
Some checks failed
CD Pipeline / deploy (push) Failing after 1m4s
2026-05-20 09:54:24 +08:00
OoO
0242aebb66 新增 PChome 覆核匯出與診斷原因
All checks were successful
CD Pipeline / deploy (push) Successful in 1m3s
2026-05-20 09:48:25 +08:00
OoO
ac93d185f4 新增市場情報 AI summary Telegram dispatch gate
All checks were successful
CD Pipeline / deploy (push) Successful in 1m36s
2026-05-20 09:23:45 +08:00
OoO
3090b18fa4 補齊比價覆核狀態分流
All checks were successful
CD Pipeline / deploy (push) Successful in 1m9s
2026-05-20 09:18:49 +08:00
OoO
c9a5478fef 同步競品情報 repository 模組化盤點 2026-05-20 01:39:29 +08:00
OoO
c9aa2efd8b 補齊比價覆核隊列分頁
All checks were successful
CD Pipeline / deploy (push) Successful in 1m3s
2026-05-20 01:35:10 +08:00
OoO
b2f9ccf4f0 新增市場情報 AI summary persistence run closeout
Some checks failed
CD Pipeline / deploy (push) Has been cancelled
2026-05-20 01:34:47 +08:00
OoO
c9d2ff330f 修正商品看板覆核快取回填
All checks were successful
CD Pipeline / deploy (push) Successful in 1m4s
2026-05-20 01:21:33 +08:00
OoO
51daa86735 新增市場情報 AI summary persistence run receipt
All checks were successful
CD Pipeline / deploy (push) Successful in 1m3s
2026-05-20 01:16:54 +08:00
OoO
9ba1d8aedd 校正比價覆核版本紀錄 2026-05-20 01:15:36 +08:00
OoO
2bf2245cea 串接商品看板比價覆核隊列
All checks were successful
CD Pipeline / deploy (push) Successful in 1m7s
2026-05-20 01:14:12 +08:00
OoO
baf5eb2881 新增市場情報 AI summary persistence run readiness
All checks were successful
CD Pipeline / deploy (push) Successful in 1m3s
2026-05-20 00:32:43 +08:00
OoO
cd13044849 串接 PChome 單位價覆核隊列
All checks were successful
CD Pipeline / deploy (push) Successful in 1m4s
2026-05-20 00:29:40 +08:00
OoO
36c177762f 顯示 PChome 單位價候選資訊
All checks were successful
CD Pipeline / deploy (push) Successful in 1m2s
2026-05-20 00:11:29 +08:00
OoO
89c2bc96e4 新增市場情報 AI summary persistence run package preview
All checks were successful
CD Pipeline / deploy (push) Successful in 1m3s
2026-05-20 00:09:17 +08:00
OoO
124ddc7376 加入 PChome 單位價比較證據
All checks were successful
CD Pipeline / deploy (push) Successful in 1m19s
2026-05-20 00:05:18 +08:00
OoO
108b05cc8b 收緊 PChome 單位價可比邊界
All checks were successful
CD Pipeline / deploy (push) Successful in 1m3s
2026-05-19 23:49:23 +08:00
OoO
23ddd3ede9 新增 PChome 單位價可比狀態
All checks were successful
CD Pipeline / deploy (push) Successful in 1m2s
2026-05-19 23:44:30 +08:00
OoO
809bcbbf67 新增市場情報 AI summary persistence writer preflight
All checks were successful
CD Pipeline / deploy (push) Successful in 1m3s
2026-05-19 23:39:35 +08:00
OoO
91601da3f8 [V10.289] 重排 EA HITL Telegram 告警格式 | telegram_templates.py
All checks were successful
CD Pipeline / deploy (push) Successful in 1m6s
2026-05-19 23:35:16 +08:00
OoO
645cd397c2 細分 PChome 配對拒絕狀態
All checks were successful
CD Pipeline / deploy (push) Successful in 1m4s
2026-05-19 23:31:44 +08:00
OoO
d20615992a 新增市場情報 AI summary persistence transaction preview
All checks were successful
CD Pipeline / deploy (push) Successful in 1m2s
2026-05-19 23:24:54 +08:00
OoO
032ba2bbd3 縮短 PChome feeder 外部請求 timeout
Some checks failed
CD Pipeline / deploy (push) Has been cancelled
2026-05-19 23:23:48 +08:00
OoO
205b9ea3f6 強化商品線配對與組合 veto
All checks were successful
CD Pipeline / deploy (push) Successful in 1m11s
2026-05-19 23:13:54 +08:00
OoO
6fc064cd9a 新增市場情報 AI summary persistence preflight
All checks were successful
CD Pipeline / deploy (push) Successful in 1m12s
2026-05-19 23:10:32 +08:00
OoO
3e66a71c8c 加速競品風險查詢
All checks were successful
CD Pipeline / deploy (push) Successful in 1m3s
2026-05-19 22:55:26 +08:00
OoO
d88d9b7326 刷新過期 PChome identity 價格
All checks were successful
CD Pipeline / deploy (push) Successful in 1m2s
2026-05-19 22:46:43 +08:00
OoO
cc3be7fd4f 新增市場情報 AI summary output receipt gate
All checks were successful
CD Pipeline / deploy (push) Successful in 1m3s
2026-05-19 22:41:13 +08:00
OoO
2e5ff091fa 專業化資源壓力告警語意
Some checks failed
CD Pipeline / deploy (push) Has been cancelled
2026-05-19 22:40:19 +08:00
OoO
0fc96837f4 [V10.284] 預設關閉 Code Review Hermes LLM scan | code_review_pipeline_service.py
All checks were successful
CD Pipeline / deploy (push) Successful in 1m1s
2026-05-19 22:34:30 +08:00
OoO
880d15b055 修正競品簡報覆蓋率與營運視角
All checks were successful
CD Pipeline / deploy (push) Successful in 1m2s
2026-05-19 22:33:01 +08:00
OoO
840cb0acdb [V10.283] 收斂 Code Review Hermes fast scan prompt | code_review_pipeline_service.py
All checks were successful
CD Pipeline / deploy (push) Successful in 1m2s
2026-05-19 22:30:05 +08:00
OoO
350022f2ea [V10.282] 補齊 Code Review Hermes 本地模型矩陣 | code_review_pipeline_service.py
All checks were successful
CD Pipeline / deploy (push) Successful in 1m1s
2026-05-19 22:26:09 +08:00
OoO
40ddf4eee0 強化 PChome legacy 配對重驗證
All checks were successful
CD Pipeline / deploy (push) Successful in 1m3s
2026-05-19 22:18:32 +08:00
OoO
f8222006b8 [V10.281] 強化 Code Review Ollama 本地備援矩陣 | code_review_pipeline_service.py
All checks were successful
CD Pipeline / deploy (push) Successful in 1m3s
2026-05-19 22:15:48 +08:00
OoO
f911f96d1a [V10.280] 補市場情報 Phase81 AI summary run package | market_intel
All checks were successful
CD Pipeline / deploy (push) Successful in 1m6s
2026-05-19 22:12:55 +08:00
OoO
dacf5f305a [V10.279] 補 Phase80 readiness smoke 測試 | test_market_intel_skeleton.py 2026-05-19 21:59:45 +08:00
OoO
ebddd4e063 [V10.279] 補 Phase80 AI summary preflight 單元測試 | test_market_intel_skeleton.py 2026-05-19 21:59:19 +08:00
OoO
ec3b4d9157 [V10.279] 補 Phase80 市場情報路由索引測試 | routes README
Some checks failed
CD Pipeline / deploy (push) Failing after 1m2s
2026-05-19 21:58:45 +08:00
OoO
03ab276032 [V10.279] 收斂 Code Review Ollama 路徑並補 Phase80 gate | code_review, market_intel
Some checks failed
CD Pipeline / deploy (push) Has been cancelled
2026-05-19 21:57:44 +08:00
OoO
482bfbdb64 [V10.278] 補市場情報 AI 摘要 preflight 與競價摘要快取 | market_intel, competitor_intel
All checks were successful
CD Pipeline / deploy (push) Successful in 1m5s
2026-05-19 21:54:58 +08:00
OoO
91ebb88ac4 延長競價摘要快取並在更新後失效 2026-05-19 21:54:56 +08:00
OoO
2c02e8d691 快取 PChome 競價摘要查詢
All checks were successful
CD Pipeline / deploy (push) Successful in 1m2s
2026-05-19 21:48:39 +08:00
OoO
2a7916a73f 同步市場情報 Phase79 版本紀錄 2026-05-19 21:44:11 +08:00
OoO
d2e9867823 [V10.276] 同步 EA 檔案行數治理記憶 | code_modularization_inventory_20260430.md 2026-05-19 21:43:15 +08:00
OoO
e3b4ed9d1e [V10.276] 修正 EA 價格觸發 DB 實證 prefetch | elephant_alpha_autonomous_engine.py
All checks were successful
CD Pipeline / deploy (push) Successful in 1m5s
2026-05-19 21:41:21 +08:00
OoO
6461d2453f [V10.275] 補上市場情報 archive summary UI 與測試 | disabled.html, test_market_intel_skeleton.py 2026-05-19 21:41:17 +08:00
OoO
6622aa458b 新增市場情報 review archive summary gate 2026-05-19 21:37:47 +08:00
OoO
eb5558f1e7 固定清理 action_plans 過期隊列
All checks were successful
CD Pipeline / deploy (push) Successful in 1m5s
2026-05-19 21:29:44 +08:00
OoO
2e7f2d8e94 新增市場情報 review completion archive gate
All checks were successful
CD Pipeline / deploy (push) Successful in 1m4s
2026-05-19 21:23:49 +08:00
OoO
786894f050 同步 action plan 防重版本號
All checks were successful
CD Pipeline / deploy (push) Successful in 1m2s
2026-05-19 21:21:45 +08:00
OoO
5e2186a808 防止 action_plans 重複回長
All checks were successful
CD Pipeline / deploy (push) Successful in 1m0s
2026-05-19 21:19:41 +08:00
OoO
8cd70d8326 新增市場情報 post-closeout inventory gate
All checks were successful
CD Pipeline / deploy (push) Successful in 1m2s
2026-05-19 21:10:14 +08:00
OoO
8c13c941c0 收斂 NemoTron 舊回覆行動
Some checks failed
CD Pipeline / deploy (push) Has been cancelled
2026-05-19 21:09:37 +08:00
OoO
aaebd6b86d 清理 EA 過期行動隊列
All checks were successful
CD Pipeline / deploy (push) Successful in 1m3s
2026-05-19 21:01:44 +08:00
OoO
d32b1f0e80 新增市場情報 review decision writer run closeout
All checks were successful
CD Pipeline / deploy (push) Successful in 1m3s
2026-05-19 20:52:14 +08:00
OoO
32013ae3b2 專業化 EA 資源壓力告警
All checks were successful
CD Pipeline / deploy (push) Successful in 1m2s
2026-05-19 20:47:46 +08:00
OoO
1911c1c53d 補強套組與多品項比對否決
All checks were successful
CD Pipeline / deploy (push) Successful in 1m40s
2026-05-19 18:07:26 +08:00
OoO
45eb0d8464 新增市場情報 review decision writer run receipt
All checks were successful
CD Pipeline / deploy (push) Successful in 1m4s
2026-05-19 18:04:31 +08:00
OoO
75390f8495 收緊 PChome 同款比對門檻
All checks were successful
CD Pipeline / deploy (push) Successful in 1m19s
2026-05-19 15:53:09 +08:00
OoO
6c548e2251 修正累積部署驗證測試與模組化盤點
All checks were successful
CD Pipeline / deploy (push) Successful in 1m6s
2026-05-19 15:44:22 +08:00
OoO
8fd6c4a42c 新增市場情報 review decision writer run readiness 2026-05-19 15:44:18 +08:00
OoO
dafde7e1a7 強化 MOMO PChome 比價可信鏈路
All checks were successful
CD Pipeline / deploy (push) Successful in 1m45s
2026-05-19 15:26:10 +08:00
OoO
ec378258e7 新增市場情報 review decision writer run package
All checks were successful
CD Pipeline / deploy (push) Successful in 1m4s
2026-05-19 15:14:34 +08:00
OoO
02f9b49d4d 修正市場情報 operator drill API gate
All checks were successful
CD Pipeline / deploy (push) Successful in 1m3s
2026-05-19 14:55:56 +08:00
OoO
2324c85e74 新增市場情報 review decision writer operator drill
All checks were successful
CD Pipeline / deploy (push) Successful in 1m3s
2026-05-19 14:53:36 +08:00
OoO
ac2f712354 新增市場情報 review decision writer postwrite smoke
All checks were successful
CD Pipeline / deploy (push) Successful in 1m4s
2026-05-19 14:39:35 +08:00
OoO
f046f4c07f 修正 preflight readiness planned gate
All checks were successful
CD Pipeline / deploy (push) Successful in 1m2s
2026-05-19 14:29:26 +08:00
OoO
fd34e9e97a 修復 preflight gate 與 OCLearn queue 時區
All checks were successful
CD Pipeline / deploy (push) Successful in 1m6s
2026-05-19 14:28:08 +08:00
OoO
026d11b295 新增市場情報 review decision writer preflight
All checks were successful
CD Pipeline / deploy (push) Successful in 1m51s
2026-05-19 14:25:05 +08:00
OoO
d504ddac51 修復市場情報 writer CLI lazy import
All checks were successful
CD Pipeline / deploy (push) Successful in 1m22s
2026-05-19 14:01:38 +08:00
OoO
934366bdd3 新增市場情報 review decision writer gate
All checks were successful
CD Pipeline / deploy (push) Successful in 1m7s
2026-05-19 13:59:51 +08:00
OoO
80bb654dbc 修復 AI embedding queue 原子取件
All checks were successful
CD Pipeline / deploy (push) Successful in 1m3s
2026-05-19 13:57:41 +08:00
OoO
6af0e3c77f 整理市場情報 readiness payload 格式
All checks were successful
CD Pipeline / deploy (push) Successful in 1m3s
2026-05-19 13:44:34 +08:00
OoO
995cb3fd6c 新增市場情報 queue review transaction preview
Some checks failed
CD Pipeline / deploy (push) Has been cancelled
2026-05-19 13:43:26 +08:00
OoO
1205ce87fb 預熱活動看板 worker 快取
All checks were successful
CD Pipeline / deploy (push) Successful in 1m2s
2026-05-19 13:34:06 +08:00
OoO
48dd9c5094 新增市場情報 queue review approval gate
All checks were successful
CD Pipeline / deploy (push) Successful in 1m1s
2026-05-19 13:29:40 +08:00
OoO
f288ef7031 預熱每個首頁 worker 快取
All checks were successful
CD Pipeline / deploy (push) Successful in 1m3s
2026-05-19 13:27:32 +08:00
OoO
1d3da03eee 加速成長分析指紋快取
All checks were successful
CD Pipeline / deploy (push) Successful in 1m2s
2026-05-19 13:24:11 +08:00
OoO
4a0a8bf75b 新增市場情報 queue review decision
All checks were successful
CD Pipeline / deploy (push) Successful in 1m3s
2026-05-19 13:16:59 +08:00
OoO
16a1f22bd8 加速當日業績 metadata 查詢
All checks were successful
CD Pipeline / deploy (push) Successful in 1m3s
2026-05-19 13:07:57 +08:00
OoO
6788379d10 抑制 EA 無實證空告警
All checks were successful
CD Pipeline / deploy (push) Successful in 1m2s
2026-05-19 13:04:01 +08:00
OoO
6fa425fb41 穩定活動看板共享快取
All checks were successful
CD Pipeline / deploy (push) Successful in 1m2s
2026-05-19 13:01:04 +08:00
OoO
bdae154237 新增市場情報 queue review inventory
Some checks failed
CD Pipeline / deploy (push) Has been cancelled
2026-05-19 13:00:46 +08:00
OoO
e7e045253d 補 OpenClaw QA 備援與市場情報交接
All checks were successful
CD Pipeline / deploy (push) Successful in 1m4s
2026-05-19 12:46:43 +08:00
OoO
8d0c442bdd 穩定成長分析共享快取
All checks were successful
CD Pipeline / deploy (push) Successful in 1m2s
2026-05-19 12:44:17 +08:00
OoO
45ae7a3d88 修正 Code Review Gemini 備援遙測
All checks were successful
CD Pipeline / deploy (push) Successful in 1m6s
2026-05-19 12:31:48 +08:00
OoO
04844099d9 新增市場情報 queue writer closeout
All checks were successful
CD Pipeline / deploy (push) Successful in 1m10s
2026-05-19 12:21:58 +08:00
OoO
2d4a3a4bf9 新增市場情報 queue writer run receipt 2026-05-19 12:04:28 +08:00
OoO
c55c74b999 強化 PPT 視覺 QA runtime 顯示
All checks were successful
CD Pipeline / deploy (push) Successful in 1m5s
2026-05-19 11:59:18 +08:00
OoO
1274dadfa1 新增市場情報 queue writer run readiness
All checks were successful
CD Pipeline / deploy (push) Successful in 1m3s
2026-05-19 11:40:55 +08:00
OoO
21053aeb50 修正 PPT 類型按鈕響應式溢出
Some checks failed
CD Pipeline / deploy (push) Has been cancelled
2026-05-19 11:40:07 +08:00
OoO
d2d6bcd263 重整 PPT 視覺 QA 產線首屏
All checks were successful
CD Pipeline / deploy (push) Successful in 1m5s
2026-05-19 11:37:18 +08:00
OoO
6086f2e0f7 移除資料協作入口錯站文案
All checks were successful
CD Pipeline / deploy (push) Successful in 1m3s
2026-05-19 11:10:01 +08:00
OoO
ffe0a0f512 修正外部工具入口橋接
All checks were successful
CD Pipeline / deploy (push) Successful in 1m4s
2026-05-19 11:07:33 +08:00
OoO
8301f0ac7e 修正市場情報 run package 版本紀錄 2026-05-19 11:03:50 +08:00
OoO
98a0ca7af9 新增市場情報 queue writer run package
All checks were successful
CD Pipeline / deploy (push) Successful in 1m4s
2026-05-19 11:01:02 +08:00
OoO
ac5d1a2d81 補業績圖表 runtime QA
All checks were successful
CD Pipeline / deploy (push) Successful in 1m6s
2026-05-19 10:40:22 +08:00
OoO
ac1bdb7812 新增市場情報佇列 writer operator drill
All checks were successful
CD Pipeline / deploy (push) Successful in 1m3s
2026-05-19 10:33:21 +08:00
OoO
e217865ccc 新增市場情報佇列寫入後 smoke
All checks were successful
CD Pipeline / deploy (push) Successful in 1m3s
2026-05-19 10:11:14 +08:00
OoO
c383a37f3f 補 PPT 視覺 QA stale recovery
All checks were successful
CD Pipeline / deploy (push) Successful in 1m4s
2026-05-19 10:03:10 +08:00
OoO
20d22b69ea 新增市場情報候選佇列 writer transaction
All checks were successful
CD Pipeline / deploy (push) Successful in 1m18s
2026-05-19 09:57:59 +08:00
OoO
cb0446e85f 限制 PPT 視覺 QA 投影片抽查
All checks were successful
CD Pipeline / deploy (push) Successful in 1m3s
2026-05-19 09:48:00 +08:00
OoO
c0ba5e876a 新增市場情報候選佇列 writer preflight
All checks were successful
CD Pipeline / deploy (push) Successful in 1m1s
2026-05-19 09:42:16 +08:00
OoO
abe3be2ffa 調整 PPT 視覺 QA timeout
All checks were successful
CD Pipeline / deploy (push) Successful in 1m2s
2026-05-19 09:30:58 +08:00
OoO
9ada594197 新增市場情報候選佇列 writer gate
Some checks failed
CD Pipeline / deploy (push) Has been cancelled
2026-05-19 09:30:10 +08:00
OoO
21cdbdb75c 修正 PPT 視覺 QA 多 worker 狀態
All checks were successful
CD Pipeline / deploy (push) Successful in 1m2s
2026-05-19 09:15:31 +08:00
OoO
583e318295 補 PPT 視覺 QA 背景狀態
All checks were successful
CD Pipeline / deploy (push) Successful in 1m6s
2026-05-19 09:06:11 +08:00
OoO
595c88fa1e 新增市場情報候選佇列交易預覽
All checks were successful
CD Pipeline / deploy (push) Successful in 1m18s
2026-05-19 01:27:45 +08:00
OoO
60bc8bf2e2 補 PPT 視覺 QA runtime checklist
All checks were successful
CD Pipeline / deploy (push) Successful in 1m6s
2026-05-19 01:24:07 +08:00
OoO
7572622cb5 新增市場情報候選送審 gate
All checks were successful
CD Pipeline / deploy (push) Successful in 1m4s
2026-05-19 01:16:15 +08:00
OoO
4a6f6a2007 補 PPT 報表覆蓋矩陣
All checks were successful
CD Pipeline / deploy (push) Successful in 1m4s
2026-05-19 01:09:58 +08:00
OoO
f6d34628f6 新增市場情報候選審核佇列草案
All checks were successful
CD Pipeline / deploy (push) Successful in 1m4s
2026-05-19 01:05:27 +08:00
OoO
7a6afa3055 新增市場情報候選活動交接預覽
All checks were successful
CD Pipeline / deploy (push) Successful in 1m3s
2026-05-19 00:54:41 +08:00
OoO
c08f76f315 補 PPT AiderHeal 執行狀態
All checks were successful
CD Pipeline / deploy (push) Successful in 1m5s
2026-05-19 00:49:06 +08:00
OoO
83fd05d614 補市場情報樣本審核 CSRF
All checks were successful
CD Pipeline / deploy (push) Successful in 1m2s
2026-05-19 00:45:14 +08:00
OoO
f221832735 新增市場情報樣本結果即時審核
All checks were successful
CD Pipeline / deploy (push) Successful in 1m3s
2026-05-19 00:41:53 +08:00
OoO
e60707cdfb 補 PPT AiderHeal 去重鎖
All checks were successful
CD Pipeline / deploy (push) Successful in 1m5s
2026-05-19 00:35:11 +08:00
OoO
02682c81ed 讓 PPT AiderHeal 背景派工
All checks were successful
CD Pipeline / deploy (push) Successful in 1m5s
2026-05-19 00:30:24 +08:00
OoO
5908d1bdca 新增市場情報樣本結果審核預覽
All checks were successful
CD Pipeline / deploy (push) Successful in 1m4s
2026-05-19 00:28:20 +08:00
OoO
2de9386a40 修正 PPT AiderHeal 派工
All checks were successful
CD Pipeline / deploy (push) Successful in 1m5s
2026-05-19 00:23:32 +08:00
OoO
cd08dd7f97 新增市場情報樣本驗收契約
All checks were successful
CD Pipeline / deploy (push) Successful in 1m1s
2026-05-19 00:18:10 +08:00
OoO
dddafc579b 強化 PPT 視覺問題追蹤
All checks were successful
CD Pipeline / deploy (push) Successful in 1m6s
2026-05-19 00:16:21 +08:00
OoO
774f1b4b45 新增市場情報人工樣本抓取計畫
All checks were successful
CD Pipeline / deploy (push) Successful in 1m3s
2026-05-19 00:09:56 +08:00
OoO
f51dc173f7 補 PPT 視覺 QA 診斷摘要
All checks were successful
CD Pipeline / deploy (push) Successful in 1m8s
2026-05-19 00:04:27 +08:00
OoO
1cf1fd01b1 修正 Ollama fallback 與 PPT vision payload
All checks were successful
CD Pipeline / deploy (push) Successful in 1m30s
2026-05-18 21:32:15 +08:00
OoO
aa8c2c7148 補強 PPT 視覺 QA 補跑與全類型審核
All checks were successful
CD Pipeline / deploy (push) Successful in 1m5s
2026-05-18 20:57:34 +08:00
OoO
be0dd41472 新增 PPT 審核歷史同頁回放
All checks were successful
CD Pipeline / deploy (push) Successful in 1m5s
2026-05-18 20:40:25 +08:00
OoO
e880c91028 新增市場情報 DB 庫存只讀總覽
All checks were successful
CD Pipeline / deploy (push) Successful in 1m3s
2026-05-18 20:37:04 +08:00
OoO
0609194ef5 修正 PPT 預覽抽屜標題選擇器
All checks were successful
CD Pipeline / deploy (push) Successful in 1m3s
2026-05-18 20:33:38 +08:00
OoO
b8fe5f0c58 新增 PPT 同頁 PDF 預覽抽屜
All checks were successful
CD Pipeline / deploy (push) Successful in 1m4s
2026-05-18 20:28:49 +08:00
OoO
c4b92ce9f5 新增市場情報正式 DB 只讀 smoke
All checks were successful
CD Pipeline / deploy (push) Successful in 1m55s
2026-05-18 20:26:04 +08:00
OoO
36e20216ed 新增市場情報 DB catalog 判讀
All checks were successful
CD Pipeline / deploy (push) Successful in 1m4s
2026-05-18 20:18:03 +08:00
OoO
9a88b32e90 新增 PPT 本頁批次預熱
All checks were successful
CD Pipeline / deploy (push) Successful in 1m5s
2026-05-18 20:15:26 +08:00
OoO
841443f37c 新增市場情報 migration 套用演練
All checks were successful
CD Pipeline / deploy (push) Successful in 1m2s
2026-05-18 20:05:24 +08:00
OoO
48d71c711b 新增 PPT 預覽快取預熱操作
All checks were successful
CD Pipeline / deploy (push) Successful in 1m7s
2026-05-18 20:03:19 +08:00
OoO
bc900321f8 feat(market-intel): add alert review queue migration blueprint
All checks were successful
CD Pipeline / deploy (push) Successful in 1m1s
2026-05-18 19:51:36 +08:00
OoO
7e2f1ac671 標示 PPT 預覽快取狀態
All checks were successful
CD Pipeline / deploy (push) Successful in 1m5s
2026-05-18 19:48:14 +08:00
OoO
96533a1c20 feat(market-intel): add alert review queue contract
All checks were successful
CD Pipeline / deploy (push) Successful in 1m3s
2026-05-18 19:41:35 +08:00
OoO
841db133d0 refactor(market-intel): modularize deployment readiness
All checks were successful
CD Pipeline / deploy (push) Successful in 1m13s
2026-05-18 19:36:19 +08:00
OoO
d946c1abab 讓 PPT 異常隊列可重跑報表
All checks were successful
CD Pipeline / deploy (push) Successful in 1m5s
2026-05-18 19:32:28 +08:00
OoO
43773e871c feat(market-intel): add alert review preview
All checks were successful
CD Pipeline / deploy (push) Successful in 1m4s
2026-05-18 19:27:54 +08:00
OoO
9981bc9d22 強化 PPT 異常優先隊列
All checks were successful
CD Pipeline / deploy (push) Successful in 1m5s
2026-05-18 19:21:44 +08:00
OoO
9ed0805697 feat(market-intel): add opportunity alert plan preview
All checks were successful
CD Pipeline / deploy (push) Successful in 1m2s
2026-05-18 19:18:00 +08:00
OoO
b5511e818f 優化 PPT 產線工作隊列
All checks were successful
CD Pipeline / deploy (push) Successful in 1m5s
2026-05-18 19:13:50 +08:00
OoO
8f6b3a4b41 feat(market-intel): add opportunity evidence plan preview
All checks were successful
CD Pipeline / deploy (push) Successful in 1m4s
2026-05-18 19:07:45 +08:00
OoO
ebbf7bc063 優化 PPT 產線健康總覽
All checks were successful
CD Pipeline / deploy (push) Successful in 1m6s
2026-05-18 19:00:18 +08:00
OoO
f5b9f1bd74 feat(market-intel): add opportunity scoring plan preview
Some checks failed
CD Pipeline / deploy (push) Has been cancelled
2026-05-18 18:59:41 +08:00
OoO
18f8038b01 feat(market-intel): add opportunity plan preview
All checks were successful
CD Pipeline / deploy (push) Successful in 1m2s
2026-05-18 16:16:55 +08:00
OoO
0fcc0ea265 feat(market-intel): add match review plan preview
All checks were successful
CD Pipeline / deploy (push) Successful in 1m2s
2026-05-18 16:08:42 +08:00
OoO
1262017261 優化 PPT 最近預覽入口
Some checks failed
CD Pipeline / deploy (push) Has been cancelled
2026-05-18 16:07:55 +08:00
OoO
217aa4fd6d 微調 PPT 產線狀態文案
All checks were successful
CD Pipeline / deploy (push) Successful in 1m10s
2026-05-18 15:57:13 +08:00
OoO
a3fb476eed feat(market-intel): add scheduler attach plan preview
Some checks failed
CD Pipeline / deploy (push) Failing after 45s
2026-05-18 15:48:59 +08:00
OoO
d2d8dbab65 強化 PPT 產線與線上預覽
Some checks failed
CD Pipeline / deploy (push) Has been cancelled
2026-05-18 15:44:11 +08:00
OoO
921e9eeb15 feat(market-intel): gate manual fetch behind mcp readiness
All checks were successful
CD Pipeline / deploy (push) Successful in 1m6s
2026-05-18 15:40:56 +08:00
OoO
d990316d74 feat(market-intel): add mcp activation runbook
All checks were successful
CD Pipeline / deploy (push) Successful in 1m4s
2026-05-18 15:25:44 +08:00
OoO
634d6ba457 修正業績圖表資料載入
All checks were successful
CD Pipeline / deploy (push) Successful in 1m4s
2026-05-18 15:03:41 +08:00
OoO
160173a270 fix(market-intel): mount mcp compose for preflight
All checks were successful
CD Pipeline / deploy (push) Successful in 6m28s
2026-05-18 14:55:02 +08:00
OoO
6f68178959 feat(market-intel): add external mcp preflight
All checks were successful
CD Pipeline / deploy (push) Successful in 1m2s
2026-05-18 14:51:47 +08:00
OoO
02339c93e0 fix: match promo ppt coverage labels
All checks were successful
CD Pipeline / deploy (push) Successful in 1m3s
2026-05-18 14:44:54 +08:00
OoO
07b76870c9 feat(market-intel): add internal mcp contract
All checks were successful
CD Pipeline / deploy (push) Successful in 1m1s
2026-05-18 14:42:25 +08:00
OoO
b8ca756090 fix: align ppt auto generation targets
All checks were successful
CD Pipeline / deploy (push) Successful in 1m4s
2026-05-18 14:39:43 +08:00
OoO
45af902b63 feat(market-intel): add mcp readiness preview
All checks were successful
CD Pipeline / deploy (push) Successful in 1m2s
2026-05-18 14:31:52 +08:00
OoO
a6059b5377 fix: restore analysis chart rendering 2026-05-18 14:24:28 +08:00
OoO
49f6b3ebd9 fix: parameterize import snapshot date filters
All checks were successful
CD Pipeline / deploy (push) Successful in 1m3s
2026-05-18 14:23:49 +08:00
OoO
cb02cd350f feat: schedule full ppt auto generation cadence
Some checks failed
CD Pipeline / deploy (push) Has been cancelled
2026-05-18 14:22:09 +08:00
OoO
bb6a862dbe feat(market-intel): 新增既有資料橋接預覽
All checks were successful
CD Pipeline / deploy (push) Successful in 1m2s
2026-05-18 14:19:43 +08:00
OoO
c021945047 fix: route telegram vision through ollama first
All checks were successful
CD Pipeline / deploy (push) Successful in 1m4s
2026-05-18 14:07:49 +08:00
OoO
b361ca7723 Fix V3 shell active states
All checks were successful
CD Pipeline / deploy (push) Successful in 1m3s
2026-05-18 12:18:00 +08:00
OoO
f73a1710c4 Sync observability CSS mirror
All checks were successful
CD Pipeline / deploy (push) Successful in 1m6s
2026-05-18 12:01:27 +08:00
OoO
c420d48263 Fix PPT auto generation and analytics fallbacks
Some checks failed
CD Pipeline / deploy (push) Failing after 26s
2026-05-18 11:52:31 +08:00
OoO
3284b1cf82 perf: 收斂當日業績前端事件綁定
All checks were successful
CD Pipeline / deploy (push) Successful in 1m4s
2026-05-18 10:44:47 +08:00
OoO
d1ff323e50 perf: 收斂商品看板前端事件與圖表載入
All checks were successful
CD Pipeline / deploy (push) Successful in 1m2s
2026-05-18 10:29:01 +08:00
OoO
4e71ed9ecd perf: 收斂活動看板前端事件與圖表載入
All checks were successful
CD Pipeline / deploy (push) Successful in 1m3s
2026-05-18 09:54:45 +08:00
OoO
e167ba1497 fix: 補上品牌 favicon 回應
All checks were successful
CD Pipeline / deploy (push) Successful in 1m7s
2026-05-18 09:39:24 +08:00
OoO
f2aece5b71 perf: 外部化觀測台圖表腳本
All checks were successful
CD Pipeline / deploy (push) Successful in 1m9s
2026-05-18 09:30:34 +08:00
OG T
d03a636baa fix(telegram): redact bot api logs
All checks were successful
CD Pipeline / deploy (push) Successful in 1m4s
2026-05-18 09:03:50 +08:00
OoO
81f4a0d18a perf: 延後載入業績圖表資源
All checks were successful
CD Pipeline / deploy (push) Successful in 1m6s
2026-05-18 08:51:09 +08:00
OoO
3a779ca075 ci: 支援外部化底板觀測台檢查
All checks were successful
CD Pipeline / deploy (push) Successful in 1m11s
2026-05-18 00:41:22 +08:00
OoO
ebc6f2cfe5 perf: 外部化共用底板資源
Some checks failed
CD Pipeline / deploy (push) Failing after 27s
2026-05-18 00:31:21 +08:00
OoO
cf52b07809 perf: 外部化商品看板前端資源
All checks were successful
CD Pipeline / deploy (push) Successful in 1m5s
2026-05-18 00:22:10 +08:00
OoO
53e9a57baf perf: 收斂當日業績明細首屏
All checks were successful
CD Pipeline / deploy (push) Successful in 1m5s
2026-05-18 00:08:50 +08:00
OoO
32801b5d57 perf: 啟用靜態資源版本快取
All checks were successful
CD Pipeline / deploy (push) Successful in 1m3s
2026-05-18 00:03:08 +08:00
OoO
e868a66058 perf: 外部化活動看板前端資源
All checks were successful
CD Pipeline / deploy (push) Successful in 1m4s
2026-05-17 23:57:05 +08:00
OoO
856075bb4d perf: 降低活動看板預設分頁量
All checks were successful
CD Pipeline / deploy (push) Successful in 1m5s
2026-05-17 23:44:03 +08:00
OoO
4736a7f7df perf: 減輕活動看板首屏載入
All checks were successful
CD Pipeline / deploy (push) Successful in 1m3s
2026-05-17 23:38:06 +08:00
OoO
ff49d31f73 fix: 強化 AI 觀測台新版視覺規範
All checks were successful
CD Pipeline / deploy (push) Successful in 1m9s
2026-05-17 22:50:18 +08:00
OoO
de60792b7e fix: 收斂帳號安全頁新版樣式
All checks were successful
CD Pipeline / deploy (push) Successful in 1m3s
2026-05-17 22:34:09 +08:00
OoO
a9b5385615 fix: 收斂 PChome 工具頁新版樣式
All checks were successful
CD Pipeline / deploy (push) Successful in 1m4s
2026-05-17 22:13:46 +08:00
OoO
5690d79a40 fix: 收斂系統管理頁新版樣式
All checks were successful
CD Pipeline / deploy (push) Successful in 1m4s
2026-05-17 21:41:05 +08:00
OoO
14d645b4b1 fix: 清理系統頁舊色碼殘留
All checks were successful
CD Pipeline / deploy (push) Successful in 1m2s
2026-05-17 21:29:36 +08:00
OoO
f7726bea3f fix: 收斂登入與載入元件新版視覺
All checks were successful
CD Pipeline / deploy (push) Successful in 1m4s
2026-05-17 21:22:03 +08:00
OoO
938b9fe963 fix: 修正 CD 同步判斷與正式版本驗證
All checks were successful
CD Pipeline / deploy (push) Successful in 1m5s
2026-05-17 21:01:33 +08:00
OoO
7c37f066e8 統一舊模板入口新版設計
All checks were successful
CD Pipeline / deploy (push) Successful in 57s
2026-05-17 20:30:07 +08:00
OoO
626a2ed50a fix: guard ppt audit file integrity and disable preview on corrupted files 2026-05-15 14:17:33 +08:00
OoO
0b415d965b feat: 补齐 ppt_history 的 DB-backed 檔案回填並保留開啟/下載
All checks were successful
CD Pipeline / deploy (push) Successful in 59s
2026-05-15 14:14:07 +08:00
OoO
40d4d01007 feat: add ppt file view/download actions in observability audit page
All checks were successful
CD Pipeline / deploy (push) Successful in 58s
2026-05-15 14:11:04 +08:00
OoO
34b1fdf829 fix: align ppt audit history UI and reporting flow
All checks were successful
CD Pipeline / deploy (push) Successful in 59s
2026-05-15 14:08:15 +08:00
OoO
9dfb7d1514 統一登入與廠商工具頁新版設計
All checks were successful
CD Pipeline / deploy (push) Successful in 58s
2026-05-14 20:43:21 +08:00
OoO
87a83aed64 統一系統工具頁新版殼層
All checks were successful
CD Pipeline / deploy (push) Successful in 1m3s
2026-05-14 18:02:03 +08:00
OoO
869cf2da31 統一工具頁新版殼層
All checks were successful
CD Pipeline / deploy (push) Successful in 59s
2026-05-14 00:57:29 +08:00
OoO
93fa0c238a 校準通知模板頁籤標題
All checks were successful
CD Pipeline / deploy (push) Successful in 55s
2026-05-14 00:49:49 +08:00
OoO
6aae2908e0 收斂通知模板桌面表格寬度
All checks were successful
CD Pipeline / deploy (push) Successful in 56s
2026-05-14 00:47:05 +08:00
OoO
2c869edcb1 統一系統管理頁新版殼層
All checks were successful
CD Pipeline / deploy (push) Successful in 1m0s
2026-05-14 00:43:55 +08:00
OoO
3263e1b400 收窄廠商模板載入範圍
All checks were successful
CD Pipeline / deploy (push) Successful in 57s
2026-05-14 00:11:03 +08:00
OoO
e006814ed5 收斂成長分析 KPI 背景圖示
All checks were successful
CD Pipeline / deploy (push) Successful in 58s
2026-05-14 00:05:34 +08:00
OoO
4418599f46 修正廠商模板載入優先序
All checks were successful
CD Pipeline / deploy (push) Successful in 56s
2026-05-14 00:00:46 +08:00
OoO
cc2b1f576c 修正 Code Review 手機排版
All checks were successful
CD Pipeline / deploy (push) Successful in 56s
2026-05-13 23:53:31 +08:00
OoO
178f94574b 收斂管理頁手機表格排版
All checks were successful
CD Pipeline / deploy (push) Successful in 56s
2026-05-13 23:44:32 +08:00
OoO
15b5b79a51 優化活動頁手機商品列表
All checks were successful
CD Pipeline / deploy (push) Successful in 58s
2026-05-13 23:35:37 +08:00
OoO
42de2e4d3f 擴大全站響應式守門範圍
All checks were successful
CD Pipeline / deploy (push) Successful in 57s
2026-05-13 23:17:57 +08:00
OoO
83bcf49592 收斂月總表手機分頁寬度
All checks were successful
CD Pipeline / deploy (push) Successful in 56s
2026-05-13 22:59:05 +08:00
OoO
a2ada92a49 優化核心資料表響應式排版
All checks were successful
CD Pipeline / deploy (push) Successful in 59s
2026-05-13 22:54:27 +08:00
OoO
d2709398bf 收斂月總表桌面矩陣表格
All checks were successful
CD Pipeline / deploy (push) Successful in 57s
2026-05-13 22:43:48 +08:00
OoO
9119e57a43 優化AI觀測台響應式資料表
All checks were successful
CD Pipeline / deploy (push) Successful in 59s
2026-05-13 22:32:09 +08:00
OoO
93dd1f12af 優化月總表手機圖表排版
All checks were successful
CD Pipeline / deploy (push) Successful in 57s
2026-05-13 22:17:47 +08:00
OoO
e5360844e6 優化自動匯入手機任務列表
All checks were successful
CD Pipeline / deploy (push) Successful in 57s
2026-05-13 22:06:57 +08:00
OoO
dfe18d5e60 修正成長報表手機 KPI 圖示外溢
All checks were successful
CD Pipeline / deploy (push) Successful in 57s
2026-05-13 21:57:10 +08:00
OoO
596b4b39c4 優化活動頁商品圖片載入
All checks were successful
CD Pipeline / deploy (push) Successful in 56s
2026-05-13 21:51:15 +08:00
OoO
6e933d4424 修正活動看板時段列響應式排版
All checks were successful
CD Pipeline / deploy (push) Successful in 57s
2026-05-13 21:47:32 +08:00
OoO
2234488378 fix: route special ollama fallbacks through cascade
All checks were successful
CD Pipeline / deploy (push) Successful in 57s
2026-05-13 21:41:43 +08:00
OoO
48ee9f22e5 test: pin nemotron fallback to nim path 2026-05-13 21:28:33 +08:00
OoO
f5ceb79626 chore: bump system version to V10.128
All checks were successful
CD Pipeline / deploy (push) Successful in 56s
2026-05-13 21:25:22 +08:00
OoO
84fc60c059 fix: retry nemotron qwen3 across ollama hosts
Some checks failed
CD Pipeline / deploy (push) Has been cancelled
2026-05-13 21:24:53 +08:00
OoO
ed29e66fde fix: route hermes through ollama cascade
All checks were successful
CD Pipeline / deploy (push) Successful in 57s
2026-05-13 21:21:05 +08:00
OoO
f656026082 收斂當日業績手機表格寬度
All checks were successful
CD Pipeline / deploy (push) Successful in 57s
2026-05-13 21:17:28 +08:00
OoO
d82a1671b6 fix: route openclaw qa through ollama cascade 2026-05-13 21:17:22 +08:00
OoO
b644f57084 優化當日業績手機版排版
All checks were successful
CD Pipeline / deploy (push) Successful in 56s
2026-05-13 21:14:58 +08:00
OoO
2635b22ebc 修正缺貨清單手機表頭溢出
All checks were successful
CD Pipeline / deploy (push) Successful in 56s
2026-05-13 20:16:30 +08:00
OoO
2e566ad186 優化缺貨清單新版響應式介面
All checks were successful
CD Pipeline / deploy (push) Successful in 58s
2026-05-13 20:14:59 +08:00
OoO
8a7eed3505 整理觀測台顯示字典
All checks were successful
CD Pipeline / deploy (push) Successful in 1m8s
2026-05-13 19:59:30 +08:00
OoO
250dd58172 統一觀測台新版工作台規範
All checks were successful
CD Pipeline / deploy (push) Successful in 59s
2026-05-13 19:39:33 +08:00
OoO
bc47f79a77 重整觀測台總覽新版視覺
All checks were successful
CD Pipeline / deploy (push) Successful in 58s
2026-05-13 19:19:59 +08:00
OoO
bd6310365e 停用 CICD 舊叢集副作用
Some checks failed
CD Pipeline / deploy (push) Has been cancelled
2026-05-13 19:19:15 +08:00
OoO
c5d077ff77 更新 DevOps 手冊 runtime 指令 2026-05-13 19:13:08 +08:00
OoO
c5cbc12b13 守住觀測台點陣終端層
All checks were successful
CD Pipeline / deploy (push) Successful in 58s
2026-05-13 19:07:44 +08:00
OoO
46e819a020 移除 app 入口 stale TODO banner
All checks were successful
CD Pipeline / deploy (push) Successful in 57s
2026-05-13 19:05:01 +08:00
OoO
754dc60695 記錄 V10.117 觀測台點陣契約 2026-05-13 18:57:14 +08:00
OoO
60b73e16d8 固定觀測台點陣層覆蓋順序
All checks were successful
CD Pipeline / deploy (push) Successful in 57s
2026-05-13 18:55:06 +08:00
OoO
f947469a36 融合觀測台點陣視覺語彙
All checks were successful
CD Pipeline / deploy (push) Successful in 57s
2026-05-13 18:51:46 +08:00
OoO
5a21e2394e 略過 SQLite host probe 寫入
All checks were successful
CD Pipeline / deploy (push) Successful in 58s
2026-05-13 18:50:14 +08:00
OoO
5706e19d14 記錄 V10.116 視覺契約追更 2026-05-13 18:48:32 +08:00
OoO
c10e6a45e7 記錄觀測台視覺契約守門 2026-05-13 18:47:36 +08:00
OoO
b6e65733a7 收斂觀測台手機字體與視覺契約
All checks were successful
CD Pipeline / deploy (push) Successful in 59s
2026-05-13 18:47:14 +08:00
OoO
8d36cabfb2 更新前端 V3 觀測台追更記憶 2026-05-13 16:25:37 +08:00
OoO
1bf2a6b146 守住模組化盤點行數新鮮度 2026-05-13 16:22:28 +08:00
OoO
f58c079e8b 更新模組化大檔盤點 2026-05-13 16:21:06 +08:00
OoO
342397159a 收斂 AI 觀測台 hero 高度
All checks were successful
CD Pipeline / deploy (push) Successful in 58s
2026-05-13 16:17:21 +08:00
OoO
0c89fbea63 更新 Claude 盤點接手記憶 2026-05-13 16:16:40 +08:00
OoO
b7ba54a88f 更新 ADR-017 模組化現況 2026-05-13 16:15:06 +08:00
OoO
c50180f885 補齊 AI 觀測台 badge 對比規範
All checks were successful
CD Pipeline / deploy (push) Successful in 58s
2026-05-13 16:13:05 +08:00
OoO
830661bb43 守住 app.py 不再新增路由 2026-05-13 16:12:38 +08:00
OoO
a305b26cef 記錄觀測台 V3 排版守門 2026-05-13 16:10:44 +08:00
OoO
9af95927db 修正 AI 觀測台 V3 排版規範
All checks were successful
CD Pipeline / deploy (push) Successful in 58s
2026-05-13 16:07:25 +08:00
OoO
ad5b4de4be 記錄模板與 Agent Action 守門 2026-05-13 16:06:12 +08:00
OoO
ba140f1487 移除未引用缺貨清單佔位模板
All checks were successful
CD Pipeline / deploy (push) Successful in 57s
2026-05-13 16:05:11 +08:00
OoO
ca97840e1d 守住 Agent Actions 動態白名單邊界 2026-05-13 16:03:16 +08:00
OoO
6ad002d829 記錄 Navbar 色票殘影修補 2026-05-13 16:01:55 +08:00
OoO
353295a9a1 移除舊 Navbar accent 色票殘影
All checks were successful
CD Pipeline / deploy (push) Successful in 56s
2026-05-13 16:00:51 +08:00
OoO
5547fbf307 記錄 compose 與 seed token 守門 2026-05-13 15:57:37 +08:00
OoO
621c9f2b66 守住 optional compose profile 邊界 2026-05-13 15:56:35 +08:00
OoO
7766e35578 守住 MCP compose 安全邊界 2026-05-13 15:54:46 +08:00
OoO
dc6fc6953a 守住核心容器資源與健康檢查 2026-05-13 15:53:03 +08:00
OoO
490336a764 守住 Market Intel seed token 不外洩 2026-05-13 15:51:49 +08:00
OoO
73bbc4574c 更新 Claude 盤點驗證記憶 2026-05-13 13:02:39 +08:00
OoO
ae1895ff4d 守住 compose 環境變數文件契約 2026-05-13 13:01:26 +08:00
OoO
acef0fa6ff 守住 runtime 環境變數文件契約 2026-05-13 12:59:29 +08:00
OoO
2b2233d385 補齊 OpenClaw 與 DeepSeek 環境範例 2026-05-13 12:57:46 +08:00
OoO
25e0570e80 補齊 AI runtime 環境範例 2026-05-13 12:56:14 +08:00
OoO
0bdb993914 補 OpenClaw 報表資料解析診斷
All checks were successful
CD Pipeline / deploy (push) Successful in 55s
2026-05-13 12:53:57 +08:00
OoO
bff8c4941c 補 Code Review 失敗通知診斷
Some checks failed
CD Pipeline / deploy (push) Has been cancelled
2026-05-13 12:53:01 +08:00
OoO
f4883b487c 保留 PPT Vision 主機標記失敗診斷
All checks were successful
CD Pipeline / deploy (push) Successful in 56s
2026-05-13 12:51:44 +08:00
OoO
e8497d09ea 補業績分析引導頁快取測試 2026-05-13 12:50:34 +08:00
OoO
dd8ccdf4ad 共用業績分析引導頁快取
All checks were successful
CD Pipeline / deploy (push) Successful in 55s
2026-05-13 12:50:01 +08:00
OoO
c227bb4078 補競品 Feeder 搜尋詞 fallback 診斷
All checks were successful
CD Pipeline / deploy (push) Successful in 56s
2026-05-13 12:49:03 +08:00
OoO
28c95558ab 修正挑品 Agent SQLite fallback
All checks were successful
CD Pipeline / deploy (push) Successful in 56s
2026-05-13 12:28:38 +08:00
OoO
9ec7713e6f 補 AiderHeal 靜默失敗診斷
All checks were successful
CD Pipeline / deploy (push) Successful in 56s
2026-05-13 12:25:35 +08:00
OoO
c78bb1d453 記錄 Market Intel 正式端只讀複核 2026-05-13 12:23:46 +08:00
OoO
ab612cb33d 補 OpenClaw 選單複核報告 2026-05-13 12:20:46 +08:00
OoO
2f67e160fa 共用當日業績頁面快取
All checks were successful
CD Pipeline / deploy (push) Successful in 55s
2026-05-13 12:19:21 +08:00
OoO
d8c7f6f19c 快取當日業績頁面 context
Some checks failed
CD Pipeline / deploy (push) Has been cancelled
2026-05-13 12:19:11 +08:00
OoO
d384c35e51 快取業績分析頁面 context 2026-05-13 12:15:51 +08:00
OoO
f8b9b1abf7 共用業績分析頁面快取
All checks were successful
CD Pipeline / deploy (push) Successful in 57s
2026-05-13 12:15:27 +08:00
OoO
5ee7fd9a17 忽略未確認設計審計 dump 2026-05-13 12:13:53 +08:00
OoO
b2ab03f0d0 入庫 responsive overflow guard 腳本
All checks were successful
CD Pipeline / deploy (push) Successful in 56s
2026-05-13 12:13:09 +08:00
OoO
ec93d09c18 收緊模組化治理掃描範圍 2026-05-13 12:12:27 +08:00
OoO
86fc9c94c7 避免商品看板冷快取阻塞
All checks were successful
CD Pipeline / deploy (push) Successful in 57s
2026-05-13 12:10:34 +08:00
OoO
0380d4c435 接上 responsive overflow quick review
Some checks failed
CD Pipeline / deploy (push) Has been cancelled
2026-05-13 12:10:08 +08:00
OoO
b65a319cb8 固化 Ollama 三主機路由紅線
Some checks failed
CD Pipeline / deploy (push) Has been cancelled
2026-05-13 12:09:40 +08:00
OoO
2130c4f54b 守住 AI provider Ollama-first
All checks were successful
CD Pipeline / deploy (push) Successful in 56s
2026-05-13 12:07:33 +08:00
OoO
0c9f9278f1 啟用 Market Intel seed writer CLI gate
All checks were successful
CD Pipeline / deploy (push) Successful in 57s
2026-05-13 12:06:02 +08:00
OoO
d6e8a4ffc9 忽略本地截圖暫存檔 2026-05-13 12:01:12 +08:00
OoO
6313fdd293 對齊 Ollama-first flag 語義
All checks were successful
CD Pipeline / deploy (push) Successful in 56s
2026-05-13 12:00:21 +08:00
OoO
ce208921af 限制 Ollama host 只能走核准節點
All checks were successful
CD Pipeline / deploy (push) Successful in 58s
2026-05-13 11:58:45 +08:00
OoO
5942e39e18 守住本機產物忽略規則 2026-05-13 11:57:17 +08:00
OoO
8b5a4a3bf4 接上 MOMO 自動比價爬蟲
All checks were successful
CD Pipeline / deploy (push) Successful in 56s
2026-05-13 11:56:21 +08:00
OoO
72daa53040 快取業績分析頁面資料
Some checks failed
CD Pipeline / deploy (push) Has been cancelled
2026-05-13 11:56:08 +08:00
OoO
d02b712439 標明 cache service 相容角色
All checks were successful
CD Pipeline / deploy (push) Successful in 57s
2026-05-13 11:54:46 +08:00
OoO
1aeb4a4b8e 移除 AI logger 未用 stack 推斷
Some checks failed
CD Pipeline / deploy (push) Has been cancelled
2026-05-13 11:54:16 +08:00
OoO
49c576bc4f 標定 PG sync 為 opt-in 工具 2026-05-13 11:53:01 +08:00
OoO
8099bb6999 守住 qwen3 現役模型路徑 2026-05-13 11:52:25 +08:00
OoO
c306fb6e19 隔離 PG sync 整合測試 2026-05-13 11:51:45 +08:00
OoO
0d68f3ea73 快取商品看板比價總覽
All checks were successful
CD Pipeline / deploy (push) Successful in 56s
2026-05-13 11:44:20 +08:00
OoO
6c236ebad0 快取當日業績頁面內容
All checks were successful
CD Pipeline / deploy (push) Successful in 55s
2026-05-13 11:35:28 +08:00
OoO
2ac751f0e5 補齊盤點修補 commit 清單 2026-05-13 11:34:35 +08:00
OoO
3c6503446d 移除未使用 runtime 依賴
All checks were successful
CD Pipeline / deploy (push) Successful in 55s
2026-05-13 11:32:59 +08:00
OoO
749eace426 移除未使用 Paramiko 依賴
Some checks failed
CD Pipeline / deploy (push) Has been cancelled
2026-05-13 11:32:04 +08:00
OoO
5b6b35f289 守住 AutoHeal inline 告警去重 2026-05-13 11:30:03 +08:00
OoO
0dcebb4798 加速成長分析冷啟動
All checks were successful
CD Pipeline / deploy (push) Successful in 56s
2026-05-13 11:29:49 +08:00
OoO
035b88cbf7 守住 AutoHeal migration guardrails 2026-05-13 11:29:04 +08:00
OoO
49212751f2 守住 RAG embedding signature migration 2026-05-13 11:28:19 +08:00
OoO
c165081b12 守住 host label migration 對齊 2026-05-13 11:27:35 +08:00
OoO
546c63fdee 守住 V2 silent failure 修補 2026-05-13 11:26:30 +08:00
OoO
dc99babdc6 移出誤入的本地變更
All checks were successful
CD Pipeline / deploy (push) Successful in 57s
2026-05-13 11:23:35 +08:00
OoO
81aa424587 守住 Observability smoke timeout
Some checks failed
CD Pipeline / deploy (push) Has been cancelled
2026-05-13 11:22:47 +08:00
OoO
4079f1c0ac 守住 CD migration 全範圍執行 2026-05-13 11:22:05 +08:00
OoO
58ba95ba5e 守住月結匯入 append 路徑 2026-05-13 11:21:08 +08:00
OoO
2e2b775608 守住 V2 import 清理狀態 2026-05-13 11:19:54 +08:00
OoO
6c86839350 守住盤點誤判依賴 2026-05-13 11:18:35 +08:00
OoO
b24241f361 守住 migration blocker 修補 2026-05-13 11:17:16 +08:00
OoO
eb6886e8e1 同步 scheduler 排程摘要
All checks were successful
CD Pipeline / deploy (push) Successful in 56s
2026-05-13 11:14:53 +08:00
OoO
8026b9379b 守住 scheduler 早晨排程錯開 2026-05-13 11:14:10 +08:00
OoO
b22cbb2aa0 守住 scheduler 失敗告警覆蓋 2026-05-13 11:13:13 +08:00
OoO
497c376b1d 記錄 AI smoke service 入口驗證 2026-05-13 11:11:38 +08:00
OoO
20ab5a7b90 快取活動看板資料指紋
All checks were successful
CD Pipeline / deploy (push) Successful in 56s
2026-05-13 11:05:52 +08:00
OoO
5b52af9e2f 補強 cache best-effort 診斷
All checks were successful
CD Pipeline / deploy (push) Successful in 56s
2026-05-13 11:04:34 +08:00
OoO
8a36856171 補強 Telegram callback 診斷
Some checks failed
CD Pipeline / deploy (push) Has been cancelled
2026-05-13 11:03:37 +08:00
OoO
f44c429a56 補強 AI logger best-effort 診斷
Some checks failed
CD Pipeline / deploy (push) Has been cancelled
2026-05-13 11:02:38 +08:00
OoO
ec5a22dd24 記錄 Telegram pending action 驗證 2026-05-13 11:01:20 +08:00
OoO
d410677e5e 加速活動看板時段載入
All checks were successful
CD Pipeline / deploy (push) Successful in 57s
2026-05-13 11:00:44 +08:00
OoO
89c400d53e 補上 OpenClaw best-effort 區塊紀錄
All checks were successful
CD Pipeline / deploy (push) Successful in 57s
2026-05-13 10:59:50 +08:00
OoO
7e928509a8 記錄 Agent Actions 動態入口驗證 2026-05-13 10:57:24 +08:00
OoO
6390c91a05 加速 AI 推薦頁首屏載入
All checks were successful
CD Pipeline / deploy (push) Successful in 58s
2026-05-13 10:46:48 +08:00
OoO
f9d3da5c16 記錄 AutoHeal DB guardrail 驗證 2026-05-13 10:39:51 +08:00
OoO
5285abe5b0 記錄 DB migration 覆蓋守門 2026-05-13 10:39:23 +08:00
OoO
4256a04508 記錄 Telegram 與 MCP 缺口驗證 2026-05-13 10:38:51 +08:00
OoO
adfcccffc1 補齊盤點修補 commit 清單
All checks were successful
CD Pipeline / deploy (push) Successful in 59s
2026-05-13 10:33:01 +08:00
OoO
4a5ae61f44 加速當日業績頁冷快取載入 2026-05-13 10:32:51 +08:00
OoO
2b1174a902 移出誤入的本地變更
All checks were successful
CD Pipeline / deploy (push) Successful in 58s
2026-05-13 10:31:52 +08:00
OoO
ae79cdd9d6 記錄依賴盤點驗證結果
Some checks failed
CD Pipeline / deploy (push) Has been cancelled
2026-05-13 10:31:00 +08:00
OoO
47c59fdd15 更新自動匯入修補記憶
All checks were successful
CD Pipeline / deploy (push) Successful in 55s
2026-05-13 10:29:11 +08:00
OoO
4e6e9bfe5d 綁定自動匯入日期查詢參數 2026-05-13 10:28:48 +08:00
OoO
e29529f2a9 校正 Observability 修補記憶 hash 2026-05-13 10:18:16 +08:00
OoO
3cb091f598 記錄 Observability fail-safe 區塊失敗
All checks were successful
CD Pipeline / deploy (push) Successful in 59s
2026-05-13 10:18:05 +08:00
OoO
0359e8154a 加速月份總表特殊趨勢載入
All checks were successful
CD Pipeline / deploy (push) Successful in 55s
2026-05-13 10:12:01 +08:00
OoO
0bc6f18732 更新 Claude 盤點修補記憶 2026-05-13 10:06:14 +08:00
OoO
5625032a8d 記錄 AI caller registry 匯入失敗
All checks were successful
CD Pipeline / deploy (push) Successful in 57s
2026-05-13 10:04:45 +08:00
OoO
0a75d11a28 記錄 Claude 成本節流檢查失敗
All checks were successful
CD Pipeline / deploy (push) Successful in 59s
2026-05-13 10:03:13 +08:00
OoO
f49413e78a 記錄 EA short-circuit 遙測失敗
All checks were successful
CD Pipeline / deploy (push) Successful in 56s
2026-05-13 10:01:46 +08:00
OoO
c300e496c5 記錄 ROI 月報反饋區塊失敗
All checks were successful
CD Pipeline / deploy (push) Successful in 55s
2026-05-13 10:00:04 +08:00
OoO
317ff1bf02 共用匯入檔名日期解析
All checks were successful
CD Pipeline / deploy (push) Successful in 57s
2026-05-13 09:58:56 +08:00
OoO
1ca535720f 改善匯入頁手機版頁首排版 2026-05-13 09:46:55 +08:00
OoO
d30b40a694 更新 Claude 盤點整改記憶 2026-05-13 09:41:21 +08:00
OoO
ba8510eac7 補齊 MCP 早退狀態
All checks were successful
CD Pipeline / deploy (push) Successful in 57s
2026-05-13 09:40:55 +08:00
OoO
d7ae243ece 清空 Telegram webhook 使用者上下文
Some checks failed
CD Pipeline / deploy (push) Has been cancelled
2026-05-13 09:40:19 +08:00
OoO
a335ab523f 修正 AutoHeal Telegram 觸發者審計
All checks were successful
CD Pipeline / deploy (push) Successful in 56s
2026-05-13 09:39:09 +08:00
OoO
5785a584c4 補齊 scheduler 觀測任務失敗告警
All checks were successful
CD Pipeline / deploy (push) Successful in 57s
2026-05-13 09:37:22 +08:00
OoO
34db2db5fd 修正 scheduler 合成告警 trace
All checks were successful
CD Pipeline / deploy (push) Successful in 57s
2026-05-13 09:35:57 +08:00
OoO
d15b2215f1 細分 MCP 呼叫遙測狀態
Some checks failed
CD Pipeline / deploy (push) Has been cancelled
2026-05-13 09:35:27 +08:00
OoO
bdb74b1354 告警 BGE embedding 一致性異常
All checks were successful
CD Pipeline / deploy (push) Successful in 55s
2026-05-13 09:34:03 +08:00
OoO
83645eaadf 記錄 Claude 盤點驗證結果 2026-05-13 09:29:48 +08:00
OoO
2068a3719d 修正 Telegram 分類按鈕預設 callback
All checks were successful
CD Pipeline / deploy (push) Successful in 55s
2026-05-13 09:27:34 +08:00
OoO
f398f97293 改善爬蟲管理手機統計卡排版 2026-05-13 09:26:21 +08:00
OoO
44eb36992e 補上 MCP filesystem 唯讀白名單
All checks were successful
CD Pipeline / deploy (push) Successful in 55s
2026-05-13 09:26:12 +08:00
OoO
6817f6437e 移除舊 SSH jump 設定殘影
All checks were successful
CD Pipeline / deploy (push) Successful in 56s
2026-05-13 09:25:01 +08:00
OoO
20cab6ed64 補上 RAG hit logger 回歸測試 2026-05-13 09:23:26 +08:00
OoO
36d0e5d5f3 標記 RAG 命中節省 LLM 呼叫
All checks were successful
CD Pipeline / deploy (push) Successful in 56s
2026-05-13 09:21:50 +08:00
OoO
5587e48d65 修正月份總表卡片標題對比 2026-05-13 09:18:23 +08:00
OoO
f2b91beb61 記錄 RAG 人工審核者 hash
All checks were successful
CD Pipeline / deploy (push) Successful in 58s
2026-05-13 09:13:29 +08:00
OoO
bb65ba71ba 補上 cache TTL 單一來源測試 2026-05-13 09:12:00 +08:00
OoO
8087d13e31 補上 MCP DB writer 失敗診斷
All checks were successful
CD Pipeline / deploy (push) Successful in 57s
2026-05-13 09:10:28 +08:00
OoO
9849c979c6 標記 aiops-core 為歷史草稿 2026-05-13 09:09:51 +08:00
OoO
992047ba2a 忽略未整合前端設計稿 2026-05-13 09:08:55 +08:00
OoO
4f62480bdb 串接 AutoHeal 共用 SSH helper
All checks were successful
CD Pipeline / deploy (push) Successful in 56s
2026-05-12 23:53:32 +08:00
OoO
c4d39cf544 串接 AiderHeal 共用 SSH helper
Some checks failed
CD Pipeline / deploy (push) Has been cancelled
2026-05-12 23:52:28 +08:00
OoO
83e7e0cceb 移除誤入 UI commit 的非前端檔案
Some checks failed
CD Pipeline / deploy (push) Has been cancelled
2026-05-12 23:52:25 +08:00
OoO
eb9cac0d19 改善活動看板手機導覽排版
All checks were successful
CD Pipeline / deploy (push) Successful in 57s
2026-05-12 23:50:18 +08:00
OoO
99edc15796 修正當日業績 KPI 數字裁切 2026-05-12 23:43:07 +08:00
OoO
b1013d1a25 鎖定 requirements 最低版本
All checks were successful
CD Pipeline / deploy (push) Successful in 57s
2026-05-12 23:41:35 +08:00
OoO
bc3f9cc61a 補上 action_plans 寫入護欄
All checks were successful
CD Pipeline / deploy (push) Successful in 57s
2026-05-12 23:35:25 +08:00
OoO
caa6263872 同步 incidents 相容欄位寫入
All checks were successful
CD Pipeline / deploy (push) Successful in 56s
2026-05-12 23:31:33 +08:00
OoO
539dea12c5 套用全站 V3 頁面樣式護欄
All checks were successful
CD Pipeline / deploy (push) Successful in 58s
2026-05-12 23:30:08 +08:00
OoO
1652ff3a59 補齊核心業務表 migration baseline
All checks were successful
CD Pipeline / deploy (push) Successful in 57s
2026-05-12 23:24:14 +08:00
OoO
14c5349b69 補齊 AI 觀測表 ORM 與 embedding 簽名
All checks were successful
CD Pipeline / deploy (push) Successful in 56s
2026-05-12 23:13:20 +08:00
OoO
fb145d6425 對齊 AI 觀測台 V3 視覺規範
All checks were successful
CD Pipeline / deploy (push) Successful in 59s
2026-05-12 23:02:02 +08:00
OoO
fccc80858d 修復 Wave 0 阻塞與 market intel 入庫 2026-05-12 22:49:56 +08:00
OoO
26669a2c6a Align global display font with V3 spec 2026-05-12 22:17:31 +08:00
OoO
e0809f2516 Align daily sales typography with V3 tokens
All checks were successful
CD Pipeline / deploy (push) Successful in 1m10s
2026-05-12 21:59:00 +08:00
OoO
b9ffecbc83 Polish daily sales mobile calendar
All checks were successful
CD Pipeline / deploy (push) Successful in 56s
2026-05-12 21:39:13 +08:00
OoO
dce2b4f0b7 Polish vendor stockout import mobile layout
All checks were successful
CD Pipeline / deploy (push) Successful in 55s
2026-05-12 21:25:28 +08:00
OoO
0133559dd4 Polish vendor stockout home mobile layout 2026-05-12 21:14:55 +08:00
OoO
d94901d82c Polish vendor stockout mobile summary 2026-05-12 20:59:50 +08:00
OoO
e401cb6034 Polish dashboard mobile KPI layout
All checks were successful
CD Pipeline / deploy (push) Successful in 57s
2026-05-12 20:38:33 +08:00
OoO
ef98eb507e Align observability UI with V3 spec
All checks were successful
CD Pipeline / deploy (push) Successful in 59s
2026-05-12 20:08:02 +08:00
OoO
fe6180b8ad Polish logs mobile layout
All checks were successful
CD Pipeline / deploy (push) Successful in 57s
2026-05-12 19:44:54 +08:00
OoO
605250619c Frontend V3 responsive production update
All checks were successful
CD Pipeline / deploy (push) Successful in 1m3s
2026-05-12 18:27:29 +08:00
OoO
28fc3587bb 統一回原本 V2.4 視覺色系
All checks were successful
CD Pipeline / deploy (push) Successful in 1m0s
2026-05-06 22:09:40 +08:00
OoO
57e4c575b1 Revert "調整暖色系為鮮明純色"
This reverts commit dc137e33ca.
2026-05-06 22:04:17 +08:00
OoO
9e857ee04a Revert "更換左上角網站 Logo"
This reverts commit ba9aecf661.
2026-05-06 22:04:17 +08:00
OoO
aff9fdec21 Revert "修正側欄 Logo 顯示比例"
This reverts commit e317a2f70a.
2026-05-06 22:04:17 +08:00
OoO
e317a2f70a 修正側欄 Logo 顯示比例
All checks were successful
CD Pipeline / deploy (push) Successful in 1m0s
2026-05-06 22:03:07 +08:00
OoO
ba9aecf661 更換左上角網站 Logo
All checks were successful
CD Pipeline / deploy (push) Successful in 1m0s
2026-05-06 21:57:15 +08:00
OoO
dc137e33ca 調整暖色系為鮮明純色
All checks were successful
CD Pipeline / deploy (push) Successful in 1m0s
2026-05-06 21:46:18 +08:00
OoO
464cb6b037 優化暖色系統與雲端匯入頁
All checks were successful
CD Pipeline / deploy (push) Successful in 1m1s
2026-05-06 21:26:15 +08:00
OoO
7bc81e966b 修復分析頁新版殼層與暖色圖表
All checks were successful
CD Pipeline / deploy (push) Successful in 59s
2026-05-06 21:01:07 +08:00
OoO
11ccda0e1c style(observability): refine navigation and data UI polish
All checks were successful
CD Pipeline / deploy (push) Successful in 58s
2026-05-06 20:54:48 +08:00
OoO
e6328e543e 修復分析頁模板與品牌標題
All checks were successful
CD Pipeline / deploy (push) Successful in 55s
2026-05-06 20:29:03 +08:00
OoO
30a173cf69 統一全站暖色視覺與市場情報骨架
All checks were successful
CD Pipeline / deploy (push) Successful in 58s
2026-05-06 20:24:46 +08:00
OoO
153e4c9734 fix(observability): revert unrelated quick review commit files
All checks were successful
CD Pipeline / deploy (push) Successful in 58s
2026-05-06 19:50:52 +08:00
OoO
308efdce25 chore(observability): clarify quick review completion copy
All checks were successful
CD Pipeline / deploy (push) Successful in 1m4s
2026-05-06 19:49:28 +08:00
OoO
dc7fe371bd test(observability): add deploy gate self-test
All checks were successful
CD Pipeline / deploy (push) Successful in 1m0s
2026-05-06 13:44:20 +08:00
OG T
0904a60237 fix(scheduler): quiet cold-start noise gates
All checks were successful
CD Pipeline / deploy (push) Successful in 1m29s
2026-05-06 00:31:30 +08:00
OoO
a6100a3d01 ci(observability): centralize deploy gate detection
All checks were successful
CD Pipeline / deploy (push) Successful in 3m2s
2026-05-05 23:47:34 +08:00
OoO
8cb82d4cd5 ci(observability): include QA entrypoints in deploy gate
Some checks failed
CD Pipeline / deploy (push) Has been cancelled
2026-05-05 23:43:34 +08:00
OoO
215bd9b73c ci(observability): verify CSS mirror instead of mutating runner
Some checks failed
CD Pipeline / deploy (push) Has been cancelled
2026-05-05 23:40:45 +08:00
OoO
4380fa641c ci(observability): gate frontend deploys with QA suite
Some checks failed
CD Pipeline / deploy (push) Has been cancelled
2026-05-05 23:39:00 +08:00
OoO
3db8f5c5b2 chore(observability): polish QA entrypoint docs
Some checks failed
CD Pipeline / deploy (push) Has been cancelled
2026-05-05 23:37:00 +08:00
OoO
7225e81c08 chore(observability): pass QA target args through quick review
All checks were successful
CD Pipeline / deploy (push) Successful in 2m7s
2026-05-05 23:32:13 +08:00
OoO
ca22b7fe7c docs(agents): index observability UI QA workflow 2026-05-05 23:29:31 +08:00
OoO
7ce74e32fe docs(memory): record observability UI QA guardrails 2026-05-05 23:28:06 +08:00
OoO
65eea5eb9a chore(observability): add noninteractive QA quick review flags
Some checks failed
CD Pipeline / deploy (push) Has been cancelled
2026-05-05 23:25:55 +08:00
OoO
ce7dd6068c docs(deploy): require observability QA for frontend changes 2026-05-05 23:24:33 +08:00
OoO
be1d1aec03 test(observability): include health in smoke suite
All checks were successful
CD Pipeline / deploy (push) Successful in 4m4s
2026-05-05 23:20:45 +08:00
OoO
cdcbcf1d80 chore(observability): centralize QA page contract
All checks were successful
CD Pipeline / deploy (push) Successful in 1m33s
2026-05-05 22:19:25 +08:00
OoO
346e9672a6 chore(observability): add CSS mirror sync helper
All checks were successful
CD Pipeline / deploy (push) Successful in 1m33s
2026-05-05 22:16:41 +08:00
OoO
15f7c8660d fix(observability): serve CSS from Flask static path
All checks were successful
CD Pipeline / deploy (push) Successful in 1m34s
2026-05-05 22:14:47 +08:00
OoO
6d015c5b6b test(observability): assert design system markers
All checks were successful
CD Pipeline / deploy (push) Successful in 2m24s
2026-05-05 22:08:44 +08:00
OoO
b21b40cae2 fix(observability): soften frontend error copy
All checks were successful
CD Pipeline / deploy (push) Successful in 1m2s
2026-05-05 21:58:49 +08:00
OoO
d93ad659ba fix(observability): polish topbar alert indicator
All checks were successful
CD Pipeline / deploy (push) Successful in 1m33s
2026-05-05 21:52:45 +08:00
OoO
422137efa8 test(observability): validate sidebar route coverage
All checks were successful
CD Pipeline / deploy (push) Successful in 1m41s
2026-05-05 21:46:28 +08:00
OoO
e7d567c6be test(observability): assert page content markers
Some checks failed
CD Pipeline / deploy (push) Failing after 4m55s
2026-05-05 15:53:39 +08:00
OoO
8643ed12ad test(observability): validate nav active page contract
Some checks failed
CD Pipeline / deploy (push) Has been cancelled
2026-05-05 15:48:39 +08:00
OoO
3fca720fa1 test(observability): guard sidebar navigation design
Some checks failed
CD Pipeline / deploy (push) Failing after 2m11s
2026-05-05 15:41:39 +08:00
OoO
6a0d5c138d test(observability): add one-shot QA suite
Some checks failed
CD Pipeline / deploy (push) Has been cancelled
2026-05-05 15:39:55 +08:00
OoO
b963dcf209 test(observability): add production page smoke check
Some checks failed
CD Pipeline / deploy (push) Has been cancelled
2026-05-05 15:35:47 +08:00
OoO
62276f8b0c chore(observability): wire UI guard into quick review
Some checks failed
CD Pipeline / deploy (push) Failing after 1m57s
2026-05-05 15:31:04 +08:00
OoO
07c9e200d0 test(observability): add UI regression guard
Some checks failed
CD Pipeline / deploy (push) Failing after 1m39s
2026-05-05 15:04:21 +08:00
OoO
fa3e0884ad docs(observability): 補齊 UI 治理規範
Some checks failed
CD Pipeline / deploy (push) Failing after 1m38s
2026-05-05 14:59:45 +08:00
OG T
ddcfd9603b fix(ops): cap momo runtime startup load
Some checks failed
CD Pipeline / deploy (push) Has been cancelled
2026-05-05 14:58:11 +08:00
OoO
ccd26415f3 fix(observability): 導入標題尺度 token 與 modal 樣式
Some checks failed
CD Pipeline / deploy (push) Has been cancelled
2026-05-05 14:54:17 +08:00
OoO
668d98cd3c fix(observability): 清理硬編碼樣式與圖表容器
Some checks failed
CD Pipeline / deploy (push) Failing after 9m49s
2026-05-05 14:41:00 +08:00
OoO
2c11a3dc81 fix(observability): 強化跨頁 responsive 與可及性
Some checks failed
CD Pipeline / deploy (push) Failing after 4m5s
2026-05-05 14:31:56 +08:00
OoO
4a745c27b4 fix(observability): 精修資料密集頁面視覺層級
Some checks failed
CD Pipeline / deploy (push) Has been cancelled
2026-05-05 14:27:43 +08:00
OoO
3b9a74773c fix(observability): 補齊精修樣式提交
Some checks are pending
CD Pipeline / deploy (push) Has started running
2026-05-05 14:20:49 +08:00
OoO
be986b8b97 fix(observability): 缺表時改為安全空狀態
Some checks failed
CD Pipeline / deploy (push) Has been cancelled
2026-05-05 14:19:09 +08:00
OoO
e28f604ec6 fix(observability): 收斂標題尺度與商業卡片排版
Some checks failed
CD Pipeline / deploy (push) Has been cancelled
2026-05-05 14:14:24 +08:00
OoO
4afcf3376b fix(observability): 統一標題字型並卡片化商業建議
Some checks failed
CD Pipeline / deploy (push) Has been cancelled
2026-05-05 14:09:41 +08:00
OG T
c7242971e3 fix(aiops): align incidents schema with autoheal model
Some checks failed
CD Pipeline / deploy (push) Has been cancelled
2026-05-05 14:08:19 +08:00
OoO
67b93a8b50 fix(observability): 統一觀測台 UI 設計系統
Some checks failed
CD Pipeline / deploy (push) Has been cancelled
2026-05-05 14:05:45 +08:00
OoO
c38f22e67a fix(observability): 修復戰情頁安全降級與樣式掛載
Some checks failed
CD Pipeline / deploy (push) Has been cancelled
2026-05-05 14:02:29 +08:00
OoO
505cbe20c7 fix(ui): 恢復側欄暖色導覽規範
Some checks failed
CD Pipeline / deploy (push) Has been cancelled
2026-05-05 13:57:41 +08:00
OoO
6f8fdc14ba fix(observability): 提升側欄子選單可讀性
Some checks failed
CD Pipeline / deploy (push) Has been cancelled
2026-05-05 13:56:26 +08:00
OoO
9b908ca426 fix(observability): 套用商業戰情頁觀測台樣式
Some checks failed
CD Pipeline / deploy (push) Has been cancelled
2026-05-05 13:53:40 +08:00
OG T
f6a2a05e3f fix(aiops): treat openclaw strategy actions as advisory
Some checks failed
CD Pipeline / deploy (push) Has been cancelled
2026-05-05 13:49:36 +08:00
OoO
c57b8f40ee feat(observability): 收尾 Agent 與商業戰情頁
All checks were successful
CD Pipeline / deploy (push) Successful in 7m39s
2026-05-05 13:36:31 +08:00
OoO
054685826a feat(observability): 重塑 AI 觀測台戰情室 UI
Some checks failed
CD Pipeline / deploy (push) Has been cancelled
2026-05-05 13:17:42 +08:00
OoO
2bb2e16442 feat(p56): deploy_doctor 擴充 — Observability + CD Pipeline 兩階段檢查
5 階段 → 7 階段:

[3/7] Ollama 主機(從 3 → 5 機)
  + 192.168.0.110:11435 (P53 K8s Nginx Proxy GCP-A)
  + 192.168.0.110:11436 (P53 K8s Nginx Proxy GCP-B)

[6/7] Observability 11 endpoint (新)
  全 prod smoke:mo.wooo.work/observability/* + api/health_indicator
  SPA shell fingerprint 偵測(size=7480 / etag e167a58a... = FAIL)
  302/308/401/403 (auth redirect) 視為 OK = login_required 正常工作
  PROD_BASE_URL env 可覆寫測 staging

[7/7] CD Pipeline (新)
  Gitea API 撈最近 3 個 run,狀態映射 OK/WARN/FAIL
  110 不可達 → 自動 WARN(不阻 deploy doctor exit code)

DB migrations 表清單 + 029 ollama_host_history / 030 ppt_audit_history_db。

本機跑實證:11 endpoint 全綠,Gitea 110 down 正確 WARN。
2026-05-05 12:27:51 +08:00
OoO
326285d8b9 test(p55): 觀測台 mutation endpoint logged-in success path 補測 (23/23 PASS)
P53 之前 mutation endpoint 只測 anon block (302),logged-in 成功路徑零覆蓋:
- /playbooks/toggle/<id>: 翻 is_active 邏輯
- /budget/force_throttle: cost_throttle.evaluate() 呼叫
- /ai_calls/trigger_code_review: code_review_pipeline 觸發
- /host_health/trigger_autoheal: autoheal playbook 觸發

新增 5 cases:
- test_playbook_toggle_404_on_missing: fetchone()=None 必回 404
- test_playbook_toggle_flips_active_flag: False→True 翻轉 + 中文 message
- test_budget_force_throttle_invokes_evaluate: monkeypatch 假 throttle service
- test_ai_calls_trigger_code_review_returns_json: 至少回 JSON 不爆
- test_host_health_trigger_autoheal_returns_json: 至少回 JSON 不爆

設計重點:對未來 service 重構容忍(status code 收 200/400/500/503)
但堅持「JSON response shape」契約 — 防 HTML error page 漏出。
2026-05-05 12:17:54 +08:00
OoO
df2311d4f0 feat(p55): 3 個圓餅圖補齊 — promotion_review/ppt_audit/budget
All checks were successful
CD Pipeline / deploy (push) Successful in 7m39s
S-1: promotion_review 蒸餾池 30d doughnut
- 取代原 col-md-2 卡片網格
- 8 種狀態各自分色:
  pending(灰) / awaiting_review(黃) / approved(綠) /
  rejected_quality(紅) / rejected_hallucination(深紅) /
  rejected_duplicate(橘) / rejected_human(暗紅) / expired(灰)
- 左圓餅 + 右表格雙視角

S-2: ppt_audit 30d 結果 doughnut
- 取代部分 col-md-2 卡片佈局
- 通過(綠)/失敗(黃)/錯誤(紅)/跳過(灰) 圓餅
- 6 個 KPI 卡併入右側 col-6 grid(總筆數/通過率/通過/issue/失敗/錯誤)
- 統一視覺語言:「圖+表」雙視角

S-3: budget 當月各 provider 成本 doughnut
- 新加 query:ai_calls.cost_usd GROUP BY provider 月初至今
- 8 個 provider 分色(本地 Ollama 綠系 vs 付費 LLM 橘紫系)
- 左圓餅 + 右表格(供應商/成本/佔比)+ 總計列

chart.js 視覺化從 7 個 → 10 個:
- hourly trend line
- 30d cost stacked bar
- 三主機 sparkline × 3
- RAG feedback doughnut
- KPI sparkline × 3 (calls/cost/errors)
- verdict doughnut
- heal 7d trend
- **promotion_review status doughnut(新)**
- **ppt_audit pass/fail doughnut(新)**
- **provider cost doughnut(新)**

Phase 38→55 累計 20 commits / 10 觀測頁 / 10 chart.js / DB 100%。

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-05 01:15:58 +08:00
OoO
90e8366a8d feat(p54): chart.js 視覺微調 — KPI sparkline + verdict 圓餅 + heal 趨勢
Some checks failed
CD Pipeline / deploy (push) Has been cancelled
R-1: ai_calls KPI 卡片加 24h sparkline
- 呼叫次數卡片下加 24px 高 mini line chart(藍)
- 成本卡片下加 sparkline(黃)
- 錯誤次數卡片下加 sparkline(紅)
- Token / 平均耗時 / RAG 命中卡片改顯示「平均 tk/call」「cache 命中數」「RAG 命中率%」
- 整排 KPI 從乾巴巴數字 → 含 24h 趨勢視覺
- 共用 chart.js dataset,無新 query

R-2: business_intel verdict 改 doughnut + 表格雙視角
- 取代原 col-md-3 卡片網格
- 左圓餅:effective(綠)/backfired(紅)/neutral(灰) 視覺比例
- 右表格:4 欄(verdict/筆數/佔比/平均 Δ)含正負色
- 與 quality_trend RAG pie chart 視覺風格統一

R-3: host_health AIOps card 加 7d 自癒成功率 sparkline
- routes/admin_observability_routes.py 新加 heal_daily query
  date_trunc('day') GROUP BY 7 天每日 success rate
- AIOps 7d card 底部加 80px 高 line chart
- Y 軸 0-100% / X 軸 7 天日期
- tooltip 顯示「ok/total 成功 (rate%)」

chart.js 視覺化從 4 個 → 7 個:
hourly trend / 30d stacked / 三主機 sparkline / RAG doughnut /
KPI sparkline × 3 / verdict doughnut / heal trend

Phase 38→54 累計 19 commits / 10 觀測頁 + topbar indicator / 7 chart.js。

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-05 01:13:31 +08:00
OoO
118f10701b test(p54): get_host_label / get_provider_tag 補測 (20/20 PASS)
P53 commit 7a10d27 加了 K8s Nginx Proxy 路由判斷
(192.168.0.110:11435/11436 → GCP-A/B),但無單測。
未來改 IP / 加 provider 容易破而不自知。

覆蓋:
- TestGetHostLabel × 9 cases:
  empty / GCP-A 直連 / GCP-B 直連 / Nginx 11435 / Nginx 11436 /
  111 備援 / 188 本地 / localhost / unknown fallback
- TestGetProviderTag × 5 cases + parametrize × 6 row:
  empty / GCP×2 路徑 / Secondary×2 路徑 / 111 / unknown
  + 6 row 對齊 migration 024 ai_calls.provider CHECK 白名單

特別防 regression:K8s 環境 192.168.0.110:11435 不再 fallback "未知"
(這正是 P53 commit 修的問題)。
2026-05-05 01:12:35 +08:00
OoO
7a10d27d61 feat(p53): K8s Nginx Proxy 支援 — host_label/provider_tag 補完
Some checks failed
CD Pipeline / deploy (push) Has been cancelled
問題:
K8s 內網無法直連 GCP 公網 11434,所以 110 跳板架了 Nginx Proxy
轉發 11435/11436 到 GCP-A/GCP-B。但 services/ollama_service.py 的
get_host_label() 只看 IP substring(34.143.170.20 / 34.21.145.224),
K8s 環境會 fallback 到「未知」造成觀測台主機標籤錯亂。

修補:
- services/ollama_service.py::get_host_label
  新增:
    192.168.0.110:11435 → "GCP-SSD(via Nginx 110)"
    192.168.0.110:11436 → "GCP-SSD-2(via Nginx 110)"
  保留:直連 GCP / 111 / 188 / localhost 既有判斷

- services/ollama_service.py::get_provider_tag(新函式)
  統一 provider 標籤判斷(之前散落 code_review_pipeline 等多處重寫):
    GCP 直連 + Nginx 11435 → 'gcp_ollama'
    GCP-B 直連 + Nginx 11436 → 'ollama_secondary'
    111 → 'ollama_111'
    其他 → 'ollama_other'
  跨環境統一:ai_calls.provider 在 docker-compose / K8s 都記同一 tag,
  跨環境統計不分裂。

- services/code_review_pipeline_service.py:233
  改用統一 get_provider_tag(),移除原本 hardcode 的 if/else IP 判斷。

- k8s/02-configmap.yaml(user 已改)
  OLLAMA_HOST_PRIMARY = http://192.168.0.110:11435 (Nginx → GCP-A)
  OLLAMA_HOST_SECONDARY = http://192.168.0.110:11436 (Nginx → GCP-B)
  OLLAMA_HOST_FALLBACK = http://192.168.0.111:11434 (內網)

driver test:
  http://34.143.170.20:11434 → GCP-SSD / gcp_ollama
  http://192.168.0.110:11435 → GCP-SSD(via Nginx 110)/ gcp_ollama
  http://192.168.0.111:11434 → 111 備援 / ollama_111

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-05 01:09:56 +08:00
OoO
a142e85880 test(p53): 觀測台 smoke 涵蓋 P38-P52 新增 11 endpoint (18/18 PASS)
戰役從 P27 6 路由擴展到 P52 共 20 路由(含 5 新 GET / 5 新 POST),
原 12 tests 只蓋 P27-31 範圍,P38-P52 共 11 endpoint 無 regression 防護。

新增測試:
- test_overview_index_200: /observability/ root index
- test_overview_dashboard_200: P45 總覽頁
- test_rag_queries_200: P51 RAG 召回詳情
- test_business_intel_200: P48 商業面 × AI 編排
- test_agent_orchestration_200: P46 Agent 編排矩陣
- test_health_indicator_api_returns_json: P52 topbar 健康燈 JSON API
- test_anon_get_redirects_to_login: 12 GET 路徑全強制 login (擴充 6→12)
- test_anon_post_blocked: 8 POST mutation 全強制 login (擴充 3→8)

prod 實證:mo.wooo.work 11 endpoint 全 Flask 200/308 服務(curl 已驗)。
20/20 routes @login_required 100% 覆蓋(python regex audit)。
2026-05-05 01:09:52 +08:00
OoO
2a3ea6f581 feat(p52): topbar 觀測台健康指示燈 + RAG 反饋圓餅圖
All checks were successful
CD Pipeline / deploy (push) Successful in 2m30s
P-1: topbar AI 觀測台 indicator(全頁可見)
- ewoooc_base.html topbar 加「🛰 AI 觀測台」icon button
- 紅色 badge 顯示告警數量(4 維度任一觸發即計數):
  • 三主機任一掛掉
  • 待審 episode > 0
  • 過去 1h 錯誤率 ≥ 30%
  • 預算任一 ≥ 90%
- 新 GET /observability/api/health_indicator
  輕量 JSON API(4 query 跨 host_health_probes/learning_episodes/
  ai_calls/ai_call_budgets)
- topbar polling 每 60s 自動刷新 + tooltip 顯示具體告警內容
- 全部頁面(包括 / 商品看板、所有觀測頁)topbar 都看得到健康狀態

P-2: quality_trend RAG 反饋圓餅圖(doughnut)
- 取代原本卡片網格佈局
- 1-5 星依綠→紅漸層著色(5=綠、3=黃、1=紅)
- 圓餅 + 右側表格雙視角(chart 配對 raw 數字)
- chart.js doughnut + tooltip 顯示筆數+佔比

效益:
- 統帥從任何頁面(不限觀測台)都能瞄一眼右上角看當前 AI 健康
- 快樂路徑:「正常」綠色 icon · 異常路徑:「紅色 badge + 數字」立即吸睛
- 圓餅圖比原網格更直觀「分布」感

Phase 38→52 累計 17 commits / 10 觀測頁 / DB 100% / 4 chart.js / 全頁 indicator。

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 20:20:34 +08:00
OoO
e0a8d87c2c feat(p51): RAG 召回詳情新頁 + overview 三主機 24h sparkline
All checks were successful
CD Pipeline / deploy (push) Successful in 2m35s
新頁 /observability/rag_queries:補完 RAG 觀測深度
之前只看 caller 級命中率,現在能看每筆查詢的真實內容。

O-1: route + template
- 篩選:時段(1/6/24/72/168h)/ caller / saved_only flag
- 整體 KPI 4 卡:總查詢 / 命中率 / saved_call 率 / 反饋平均分
- by caller 表:每個 caller 的查詢/命中/saved/反饋細節
- 最近 50 筆查詢詳情表
- 「查 hits」按鈕 → 彈 modal 載入 ai_insights JOIN 內容預覽
  (新 endpoint /observability/rag_queries/<id>/hits 回傳 JSON)

O-2: 入口
- sidebar AI 觀測 group 加「RAG 召回詳情」(11b)
- /observability/overview 入口卡升級為 9 項

O-3: overview 三主機 24h sparkline
- 每張主機卡片下方加 60px 高 chart.js sparkline
- 折線:每小時 uptime % bucket(0-100% Y 軸隱藏,純視覺)
- routes/admin_observability_routes.py::observability_overview
  新加 host_sparkline 查詢(GROUP BY host_label, hour)
- 三主機卡片視覺化升級:原本只有「100%」字,現在加趨勢線

Phase 38→51 累計 16 commits / 10 觀測頁。
觀測台戰役從「raw stats」到「視覺方格 UI 完整體」。

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 20:09:28 +08:00
OoO
87d460e243 feat(p50): chart.js 折線圖視覺化 + Playbook 一鍵啟用/停用
All checks were successful
CD Pipeline / deploy (push) Successful in 2m40s
統帥要求「視覺方格 UI/UX」:raw 表格不夠,加 chart.js 雙圖 + L2 管理。

N-1: ai_calls hourly trend chart.js(雙軸混合)
- 取代原 progress bar 表格
- 折線:呼叫數(藍)+ 錯誤次數(紅)→ 共用左軸
- 柱狀:成本 USD(黃)→ 右軸
- interaction mode index:滑鼠 hover 同時顯示三個指標
- chart.js 4.4.1 CDN 加在 {% block extra_js %}

N-2: budget 30d cost trend stacked bar chart
- 取代原 30d cost trend 表格(max-height 滾動 → 一目瞭然圖)
- 8 個 provider 各自分色
  本地 Ollama(綠系)vs 付費(橘/紫/青系)
- stacked bar:每日總成本一柱,依 provider 堆疊
- tooltip 顯示每個 provider $X.XXXX

N-3: Playbook 一鍵啟用/停用(L2 補強第 7 個)
- 新 POST /observability/playbooks/toggle/<id>
  翻轉 is_active + UPDATE updated_at
- host_health.html playbook 排行表加「切換」欄
- 動態按鈕:啟用顯示「停用」、停用顯示「啟用」
- 對應觀測台直接管理 AutoHeal 庫,不需 SSH 改 DB

L2 一鍵自動化從 6 個 → 7 個入口:
- AutoHeal / AiderHeal / Code Review / Force Throttle(既有)
- Telegram Heal / Throttle(既有)
- Playbook Toggle(Phase 50 新增)

Phase 38→50 累計 15 commits。
觀測台從 raw stats → AI 自動化專業舞台 → 視覺方格 UI 終局。

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 20:04:13 +08:00
OoO
822789c810 feat(p49): Telegram 補完 9 頁對應 + daily summary 加商業面未跟進警示
All checks were successful
CD Pipeline / deploy (push) Successful in 2m58s
M-B: Telegram 對應從 6/9 → 9/9
新增 3 個 cmd handler,對應 Phase 45-48 的 3 個新觀測頁:
- cmd:obs_overview — 一頁式總覽(三主機 24h + AI 呼叫 + 月成本 + 待審 episode)
- cmd:obs_orchestration — Agent 編排矩陣(4 Agent × Models 24h 數字)
  本地 Ollama % / RAG 命中 % / 錯誤率 + cost
- cmd:obs_business — 商業面 × AI(價格決策 7d by strategy
  + 未跟進機會 + Outcomes verdict 30d)

services/openclaw_bot/menu_keyboards.py::_submenu_observability 升級為 9 項

M-C: daily summary(每日 09:30)加商業面警示
- 從 ai_price_recommendations × action_plans 跨表 JOIN
  偵測 high-confidence (≥0.7) 卻無對應 action_plan 的「機會流失」
- 7d 內若有未跟進,daily summary 自動標 ⚠️ 警示
- 對應 Phase 48 business_intel 頁同個邏輯,閉環推送

inline keyboard 升級:日報附 6 個入口(總覽/編排/商業面/主機/AI/預算),
不再只有 4 個

Phase 38→49 累計 14 commits。觀測台戰役完整收官:
- 9 頁全部對應 Telegram cmd
- DB 22/22 = 100% 全覆蓋
- 6 個 L2 一鍵 + 3 種主動推送(即時/異常/日常)
- 日報含商業面警示

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 20:00:15 +08:00
OoO
95db06ad9d feat(p48): 商業面 × AI 編排新頁 — AI 在做什麼生意?實際生效嗎?
All checks were successful
CD Pipeline / deploy (push) Successful in 2m38s
新頁 /observability/business_intel:把 AI 觀測台從「技術面」延伸到「商業面」。
回答統帥兩大問:
1. 我們的 AI 在做什麼生意?
2. AI 動作真的有用嗎?(閉環追蹤)

新接 5 張未善用的商業面表(DB 利用率 17/22 → 22/22,100%):
- ai_price_recommendations(AI 價格建議完整明細)
- competitor_prices(競品價格快照)
- competitor_price_history(24h 抓取歷史)
- competitor_match_attempts(競品比對失敗追蹤)
- 善用 action_plans × action_outcomes JOIN(閉環)

頁面 widget(7 張卡片):
1. unfollowed alert:high-confidence 但未轉化為 action_plan 的數量
2. AI 決策 by strategy(promote/watch/hold 含平均信心 + gap% + 銷量變化)
3. 最近 20 筆 AI 建議詳細(SKU/商品/MOMO 價/PChome 價/Gap/原因)
4. **閉環學習表**:plan → outcome 全鏈追蹤
   含 verdict/before/after/變化 % — ADR-012 核心 KPI
5. Verdict 分布(effective/neutral/backfired 計數)
6. 競品比對嘗試統計(success/fail/avg_score)
7. 24h 競品價格抓取列表(SKU/商品/MOMO vs PChome gap)

入口:
- sidebar AI 觀測 group 加「商業面 × AI」(07c)
- /observability/overview 入口卡升級為 8 項

DB 全表覆蓋達成:22/22 = 100%
- Phase 47 17 表 → Phase 48 22 表
- 新接:ai_price_recommendations / competitor_prices /
        competitor_price_history / competitor_match_attempts
- 已用:ai_calls / ai_call_budgets / ai_insights / learning_episodes /
        rag_query_log / mcp_calls / incidents / heal_logs / playbooks /
        backup_log / embedding_retry_queue / agent_context /
        agent_strategy_weights / action_plans / action_outcomes /
        host_health_probes / ppt_audit_results

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 19:54:07 +08:00
OoO
2e124db602 feat(p47): 6 頁深挖資料庫 — 從 5 表 → 17 表,每頁加 3-5 個 widget
All checks were successful
CD Pipeline / deploy (push) Successful in 2m36s
統帥質疑:「6 頁內容太空洞,要更貼近資料庫裡所有數據」
盤點:DB 有 22 表,6 頁原本只用 5 表(22.7% 利用率)。
本 commit 新接 12 張既有但未用的表。

K-1 host_health(接 +5 表 → 8 表)
- 加 incidents 最近 10 筆詳細(task_name/error_type/嚴重度/狀態/重試/錯誤訊息)
- 加 heal_logs 最近 10 筆(action_type/result/耗時/incident 關聯)
- 加 playbooks 庫排行 TOP 12(success_count/fail_count/成功率/啟用狀態)
- 加 backup_log 7 日歷史(type/status/size/duration/error)
- 加 embedding_retry_queue pending/failed 警示

K-2 ai_calls(接 +3 表)
- 加 24h 每小時呼叫趨勢 bucket(含成本+錯誤+流量分布條)
- 加 by model 細分(不只 provider,到 model 版本級別)TOP 15
- 加 agent_context 最近 10 筆(OpenClaw/Hermes 對話 session preview)

K-3 budget(接 +3 表)
- 加當月 Top 5 燒錢呼叫端(caller × cost ranking)
- 加過去 30 日每日成本 by provider 趨勢表
- 加 ai_price_recommendations 7 日統計(strategy 分布 + 平均信心度)

K-4 promotion_review(接 +2 表)
- 加蒸餾池 30 日 status 分布(不只 awaiting,看 8 種完整流動)
- 加 ai_insights 最近 10 筆已晉升內容預覽
- 加 agent_strategy_weights TOP 12(OpenClaw 學習權重 + 成功率)

K-5 quality_trend(接 +3 表)
- 加 RAG 整體 feedback 1-5 分分布(過去 N 日,星等視覺)
- 加 action_plans status 分布(pending/approved/executed/rejected)
- 加 action_outcomes verdict 分布(effective/neutral/backfired
  — ADR-012 閉環學習核心 KPI)

K-6 ppt_audit_history(接 +0 表,但 deeper SQL)
- 加 30 日統計卡(total/passed/failed/error/通過率/總 issue 數/平均信心度)
- 加 Top 10 反覆失敗檔案(30d 失敗次數 + total issues)
- 加 empty state 說明(PPT_VISION_ENABLED=false 時顯示啟用步驟)

DB 利用率對應:
- Phase 38 起點:5 表(22.7%)
- Phase 39-46 累計:12 表(54.5%)
- Phase 47 收官:17 表(77.3%)
  新接:playbooks / backup_log / embedding_retry_queue / agent_context /
        ai_price_recommendations / agent_strategy_weights / action_plans /
        action_outcomes(之前已接:incidents/heal_logs/ai_insights/learning_episodes/
        rag_query_log/mcp_calls/ai_calls/host_health_probes/ppt_audit_results)

每頁 widget 數對應:
- host_health: 5 卡 → 11 卡
- ai_calls: 5 卡 → 8 卡
- budget: 4 卡 → 7 卡
- promotion_review: 2 卡 → 5 卡
- quality_trend: 4 卡 → 7 卡
- ppt_audit: 3 卡 → 6 卡

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 19:49:52 +08:00
OoO
347efb8ea1 feat(p46): Agent 編排矩陣新頁 — OpenClaw/Hermes/NemoTron/EA × Ollama × Gemini × MCP × RAG
All checks were successful
CD Pipeline / deploy (push) Successful in 2m30s
統帥要求:「好好把 OpenClaw/Hermes/NemoTron/ElephantAlpha + Ollama 多模型
+ 外部付費 Gemini + 內外 MCP + RAG 組合發揮出 AI 自動化新境界」

新頁面 /observability/agent_orchestration 一頁式呈現 4 Agent × 5 維度全景:

J-1: caller 自動分組
- OpenClaw: openclaw_qa/daily/meta/monthly/weekly/bot_main/bot_gemini/bot_nim
            + sales_copy + code_review_openclaw
- Hermes: hermes_analyst + hermes_intent + code_review_hermes
- NemoTron: nemotron_dispatch
- ElephantAlpha: ea_engine + code_review_elephant

J-2/3: 跨表 SQL JOIN(ai_calls × mcp_calls × rag_query_log)
每個 agent 顯示:
- 24h 呼叫 + Token + 成本
- 本地 Ollama 比例(細分 GCP-A/GCP-B/111)
- 付費 LLM 比例(細分 Gemini / 其他)
- MCP 編排率(透過 request_id 跨表 JOIN mcp_calls)
- RAG 命中率
- 錯誤率 + 平均耗時
- MCP server × caller 工作量明細

自動編排建議(5 條 rule-based):
1. 付費比例 > 50% 且 ollama < 20% → 改 Hermes-first 短路
2. 錯誤率 > 10% → 觸發 Code Review Pipeline
3. MCP 編排率 < 5% 但 calls > 50 → 擴大 MCP omnisearch/firecrawl
4. RAG 命中率 ≥ 40% → 推 Telegram 收 feedback 強化 promotion gate
5. 111 fallback 比例 > 20% → GCP 兩台異常,查 host_health AIOps

J-4: 入口
- sidebar AI 觀測 group 加「Agent 編排矩陣」(07b)
- /observability/overview 入口卡升級為 7 項,Agent 編排矩陣放第一

整體 KPI 卡片:
- 總呼叫 / 本地 Ollama 比例 / 付費 LLM 成本 / RAG 命中率
- 「組合發揮」一目瞭然

8 表跨 JOIN:ai_calls × mcp_calls × rag_query_log × ai_insights ×
learning_episodes × incidents × heal_logs × host_health_probes

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 19:38:10 +08:00
OoO
849e189b60 feat(p45): UI/UX 升級 ewoooc_base.html + sidebar AI 觀測 7 項 + 新增總覽頁
All checks were successful
CD Pipeline / deploy (push) Successful in 2m37s
統帥質疑:「那六頁的視覺方格 UI/UX 搞好了嗎?還有新增頁面嗎?」
回答:沒有,從 Phase 38 開始一直推遲。本 commit 補做。

I-1: 6 頁 base.html → ewoooc_base.html
- host_health / ai_calls_dashboard / budget / promotion_review /
  quality_trend / ppt_audit_history 全改
- {% extends "base.html" %} → {% extends "ewoooc_base.html" %}
- {% block content %} → {% block ewooo_content %}
- 自動繼承:sidebar 240px / topbar 64px / fonts (Inter+JetBrains+Noto Sans TC)
  / ewoooc-tokens.css / ewoooc-shell.css / search box / 米色背景

I-2: _ewoooc_shell.html 加「AI 觀測」nav group
- 7 個項目:觀測台總覽 / 主機健康 / AI 呼叫 / 預算控管 /
  RAG 晉升審核 / 反饋趨勢 / PPT 視覺審核
- 對應 active_page='obs_*',正確高亮
- 編號 07-13(系統管理改 14)

I-3: 新增頁面 /observability/ + /observability/overview
- routes/admin_observability_routes.py::observability_overview
- 單頁聚合 8 表跨 JOIN 的 KPI:
  • 三主機 24h 在線率(host_health_probes,per host card)
  • AI 呼叫 24h(ai_calls:total/tokens/cost/error rate/RAG hit/cache hit)
  • 當月成本累計
  • 預算告警(ratio ≥ alert_pct 自動列表)
  • AIOps 7d(incidents + heal_logs:自癒成功率)
  • MCP 24h(mcp_calls:tool 呼叫 + cache 率 + cost)
  • RAG 學習 30d(learning_episodes:待審 + 晉升率)
  • PPT 視覺審核 7d(ppt_audit_results:通過率)
  • 6 大子頁入口卡(含一行說明)
- 對應 Phase 44 daily Telegram summary 的 web 版本
- 全部失敗安全(個別 query 失敗只跳過該卡,不擋整頁)

升級對應:
- UI 框架:base.html → ewoooc_base.html (sidebar + topbar + token css 已生效)
- 設計憲法:8 卡片 + 8 表跨 JOIN 全景 + 一頁式總覽
- 入口:sidebar 7 項 + 觀測台首頁
- 資料表覆蓋:4 表(Phase 38)→ 8 表(Phase 45)

注意:完整 design token 重塑(Bootstrap class → --momo-* token / 焦糖橘)
留待後續 phase;本 commit 重點是「框架升級 + 新總覽頁」。

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 19:34:18 +08:00
OoO
72cbcb298f feat(p44): AI 呼叫錯誤率突增告警 + 觀測台每日 09:30 健康摘要
All checks were successful
CD Pipeline / deploy (push) Successful in 2m40s
完整 Telegram 主動推送閉環的兩大缺口:

H-1: AI 呼叫錯誤率突增偵測(每 30 min)
- run_scheduler.py::run_ai_calls_error_spike_check
  - 條件:過去 1h ai_calls 總呼叫 ≥ 20 且錯誤率 ≥ 30%
  - 抓 Top 3 problematic caller(errs ≥ 3)
  - 推 Telegram 告警 + inline 按鈕「🔬 觸發 Code Review」/「📊 查 24h AI 呼叫」
- routes/openclaw_bot_routes.py::cmd:obs_trigger_review (新 handler)
  - Telegram 內直接觸發 CodeReviewPipeline.run() in daemon thread
  - 對齊 Web /observability/ai_calls/trigger_code_review 邏輯
- 註冊:schedule.every(30).minutes

H-2: 觀測台每日 09:30 健康摘要(早晨報)
- run_scheduler.py::run_observability_daily_summary
  一頁式涵蓋:
    • 三主機 24h 在線率(host_health_probes 聚合)
    • AI 呼叫量 / Token / 24h 成本 / 當月累計
    • 24h 錯誤率 / RAG 命中率
    • 待審 episodes 數量
    • PPT 視覺審核 7d 通過率
  inline 4 個按鈕:主機健康 / AI 呼叫 / 預算 / 反饋趨勢
- 註冊:schedule.every().day.at("09:30")

完整推送閉環達成:
1. 主機 transition (Phase 43):state 變化即時告警 + 一鍵 AutoHeal
2. AI 錯誤突增 (Phase 44):30 min 內錯誤飆升即告警 + 一鍵 Code Review
3. 每日早晨報 (Phase 44):09:30 主動推全景摘要

統帥手機端不需主動開觀測台,所有重大事件主動推送。

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 19:29:28 +08:00
OoO
f10999ed1c feat(p43): Ollama 主機 state transition 自動告警 + inline AutoHeal 閉環
Some checks are pending
CD Pipeline / deploy (push) Has started running
問題:
Phase 42 加 scheduler 每 15min probe 寫入 host_health_probes,但只是
silent 累積 — 主機真的掛掉時統帥仍然要主動開觀測台才知道。

修補:
- run_scheduler.py::run_host_health_probe
  寫入 DB 之前先查同 host 的最近一筆 probe 比對
  state transition 偵測:
    healthy → unhealthy:推 P1 告警 + inline AutoHeal 按鈕
    unhealthy → healthy:推 P3 「已恢復」訊息
- run_scheduler.py::_push_host_transition_alert(新 helper)
  使用 services.telegram_templates::send_telegram_with_result
  inline keyboard 含「🩹 立即 AutoHeal {GCP-A|GCP-B|111}」按鈕
  + 「📊 查 24h 健康統計」次按鈕
  按鈕 callback_data 對齊既有 Phase 41 cmd:obs_heal handler
- Dedup:1 小時內同 host 同方向 transition 只推一次(防 flapping 洗版)
  用 host_health_probes 自身查歷史對比,無需新 dedup 表

完整閉環:
  scheduler 每 15min probe → 偵測 state transition → 推 Telegram 告警
  → 統帥點 inline button → cmd:obs_heal:{label} → AutoHeal 跑 ADR-013
  playbook → 寫入 incidents + heal_logs → 下一次 probe 偵測 unhealthy→
  healthy → 推「已恢復」訊息

至此觀測台從「raw stats dashboard」進化為:
  - 持續累積歷史(Phase 42)
  - 主動告警 + 一鍵修復(Phase 43)
  - 完整閉環自動化(從監控到復原全自動,僅關鍵節點需人工確認)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 19:26:54 +08:00
OoO
d5a4e27344 feat(p42): scheduler 每 15 分鐘自動 probe 三主機(不靠人開頁累積歷史)
Some checks failed
CD Pipeline / deploy (push) Has been cancelled
問題:
Phase 38 加了 host_health_probes 表 + 開觀測台頁面時寫一筆,但
無人開頁時沒人寫 → Telegram cmd:obs_health 顯示「24h uptime」永遠空。

修補:
- run_scheduler.py::run_host_health_probe
  - 每 15 min HTTP probe GCP-A/GCP-B/111 三主機 /api/tags
  - 寫入 host_health_probes(label/url/healthy/unhealthy_mark/
    models_count/response_ms/error_msg)
  - 失敗安全:HTTP/DB 失敗只 log warning
- run_scheduler.py::run_host_health_probe_cleanup
  - 每日 03:00 DELETE 30d 前舊資料(防表膨脹)
- 註冊到 schedule.every(15).minutes 與 schedule.every().day.at("03:00")

效果:
- Web /observability/host_health 24h 趨勢卡永遠有資料(即使無人開頁)
- Telegram cmd:obs_health 三主機在線率永遠有資料
- 三主機歷史完整保留 30 天,超出自動清理

Phase 38+39+40+41+42 觀測台戰役完整收官(7 commits)。

部署驗證:
- mo.wooo.work/observability/host_health → HTTP 200 / 42716 byte
  (Phase 38 為 39124 byte,多 3.5KB 證明 24h 趨勢/MCP/AIOps card 已上線)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 19:24:07 +08:00
OoO
4020b734a5 feat(p41): 觀測台戰役完整收官 — K8s 三主機化 + ppt RAG + TG inline action
All checks were successful
CD Pipeline / deploy (push) Successful in 2m34s
E-1: K8s configmap 對齊三主機級聯(清舊配置遺留)
- k8s/02-configmap.yaml:
  - 移除寫死的 OLLAMA_HOST=192.168.0.188:11434(早已過時)
  - 改注入 OLLAMA_HOST_PRIMARY/SECONDARY/FALLBACK 三個變數
  - llama3:70b → qwen3:8b(與目前 prod 一致)
- k8s/gcp/02-configmap.yaml:
  - 移除「OLLAMA_HOST=空 + AI_PROVIDER=gemini」自相矛盾
  - 改三主機級聯 + AI_PROVIDER=ollama(與 docker-compose.yml 一致)

E-2: ppt_audit 加 RAG「相似失敗修法」
- 對最近 3 筆 audit_status='failed'/'error' 跑 rag_service.query
- 從 ai_insights 召回相似案例(cosine ≥ 0.6, top 2)
- template 加「RAG 自動修法建議」card

E-3: Telegram obs_health/obs_budget 加 inline action button (L2)
- cmd:obs_health:任一主機標記異常時,inline 顯示「🩹 修 GCP-A/GCP-B/111」按鈕
- cmd:obs_heal:{label}:新 handler,在 Telegram 內直接觸發 AutoHeal
  (白名單 GCP-A/GCP-B/111,非 unhealthy 拒絕)
- cmd:obs_budget:warn 時 inline 顯示「 立即重算節流狀態」按鈕
- cmd:obs_force_throttle:新 handler,Telegram 內直接觸發 evaluate_throttle_status

最終升級對應:
- RAG 整合 4/6 → 5/6(補 ppt_audit)
- AI 自動化:Web L2×4 + Telegram L2×2 = 6 個一鍵自動化入口
- K8s 配置一致性:三套 (docker-compose / k8s/* / k8s/gcp/*) 統一
  指向 GCP-A → GCP-B → 111 三主機鏈

Phase 38+39+40+41 累計 7 commits 觀測台戰役完整收官。

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 19:18:23 +08:00
OoO
65f236da2d feat(p40): 觀測台收官 — 4 頁升 L2 + RAG 根因 + 蒸餾池監控
All checks were successful
CD Pipeline / deploy (push) Successful in 2m36s
接續 Phase 39 (commit 79cf08c),本 commit 完成 Phase D 最後 4 項:

D-6: quality_trend 蒸餾池 + RAG 根因
- 新「蒸餾池狀態」card:learning_episodes 各 promotion_status 分布
  (pending / awaiting_review / approved / rejected_quality /
   rejected_hallucination / rejected_duplicate / rejected_human / expired)
- 對最差 3 名 caller (avg_score < 3 且反饋 ≥ 3) 自動 RAG 根因建議
- RAG 從 ai_insights 召回相似低品質案例

D-7: ai_calls 一鍵 Code Review (L2)
- 新 POST /observability/ai_calls/trigger_code_review
  讀 git rev-parse HEAD + diff-tree 取最新變更檔案
  在 daemon thread 跑 CodeReviewPipeline.run() (5 step Hermes→
  OpenClaw→EA→NemoTron)
- 頁面新增「觸發 Code Review Pipeline」按鈕

D-8: ppt_audit 失敗 row 一鍵 AiderHeal (L2)
- 新 POST /observability/ppt_audit/trigger_aider_heal
  接收 pptx_filename + error_msg,呼叫 services/aider_heal_executor::
  execute_code_fix 自動修 services/ppt_generator.py
  AiderHeal 修完會 git push 觸發 CD
- audit_records 表中 status='failed'/'error' 的 row 自動顯示按鈕

D-9: host_health 一鍵 AutoHeal (L2)
- 新 POST /observability/host_health/trigger_autoheal
  接收 host_label,白名單對應 OLLAMA_HOST_PRIMARY/SECONDARY/FALLBACK
  防 SSRF。已標記 unhealthy 的 host 才允許觸發
  呼叫 auto_heal_service.handle_exception(error_type='ollama_unhealthy')
  跑 ADR-013 playbook(DOCKER_RESTART / SSH_CMD / ALERT_ONLY)
- 三主機 row 中 unhealthy / down 的 host 自動顯示按鈕

升級對應:
- AI 自動化:L2 從 1 個 → 4 個(budget force_throttle / Code Review /
  AiderHeal / AutoHeal)
- DB 利用率 ~60%:新增 learning_episodes 分布查詢
- RAG 整合 4/6(promotion_review + budget + quality_trend + 待 ppt_audit)

Phase 38+39+40 累計:6 commits 完成觀測台從 raw dashboard
升級到 AI 自動化專業舞台。

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 19:13:39 +08:00
OoO
79cf08c58c feat(p39): 觀測台升級 — DB + MCP + RAG + AI 自動化深度整合
All checks were successful
CD Pipeline / deploy (push) Successful in 2m30s
統帥質疑:6 頁觀測台只是 raw stats dashboard,沒展現 AI 自動化專業。
深度盤點 4 軸結果:
- DB 利用率 22.7%(22 表只用 5 張)
- MCP 整合 1/6(mcp_calls 表完全沒被讀)
- RAG 整合 0/6(沒 import rag_service)
- AI 自動化 L0 × 5 + L1 × 1(純讀 dashboard,無一鍵觸發)

本 commit 5 個增強:

D-1: promotion_review 加 RAG「Top 3 相似已晉升」
- 對每筆 awaiting_review episode 跑 rag_service.query 找 ai_insights 中
  cosine ≥ 0.7 的相似已晉升內容
- 輔助人工判斷:是否冗餘?是否新領域?
- header 顯示 ai_insights 知識庫 size
- fail-safe: 單筆 RAG 失敗不影響其餘

D-2: host_health 加 MCP 24h 工作量 widget
- 從 mcp_calls 統計各 server 24h 呼叫次數 / 成功率 / cache 率 /
  使用 tool 數 / 平均耗時 / cost
- 展現「AI×MCP 編排規模」而非只「server 健康與否」

D-3: ai_calls × rag_query_log × mcp_calls 三表 JOIN
- 新增「呼叫端 × RAG × MCP 編排矩陣」card
- 每個 caller:總呼叫 / RAG 命中率 / MCP 編排率(透過 request_id 串接)
  / RAG 反饋分數 / 反饋筆數
- 展現「AI 自動化專業」核心指標

D-4: budget 加 RAG 自動策略建議 + 一鍵 force-throttle (L2)
- ratio ≥ 0.8 時自動 RAG 召回 ai_insights 中的 budget_strategy 知識
- POST /budget/force_throttle endpoint:立即重算 cost_throttle 狀態
  (不等下次每小時 cron)— 升級到 L2 自動化
- 對應頁面加「立即重算節流狀態」按鈕

D-5: host_health 加 incidents + heal_logs 7d 摘要
- 顯示 ADR-013 AutoHeal 閉環核心 KPI:
  總事件 / 未解決 / 已解決 / P0+P1 / 自癒成功率 / 平均自癒耗時
- 展現「AIOps 自癒系統」運作實況

對應升級:
- DB 利用率 22.7% → ~50%(新接 mcp_calls + rag_query_log JOIN
  + ai_insights + incidents + heal_logs)
- MCP 整合 1/6 → 3/6(host_health + ai_calls + budget 都接 mcp_calls)
- RAG 整合 0/6 → 3/6(promotion_review + budget + 待 quality_trend)
- AI 自動化 L1 → L2 一鍵 force-throttle 一個(其餘按鈕待 D-6)

全部 fail-safe:DB 表/RAG/MCP 失敗都不擋頁面渲染。

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 19:08:41 +08:00
OoO
5935a6512c feat(p38): Telegram 補 4 個 AI 觀測台命令(B-3 完成)
All checks were successful
CD Pipeline / deploy (push) Successful in 2m31s
統帥盤點要求:6 個觀測頁是否都有 Telegram 對應?
盤點結果:promotion_review 已有 (pg_ok/pg_no inline button),剩 4 個缺。

新增 4 個 cmd handler 對應 4 個觀測頁面:
1. cmd:obs_ai_calls — AI 呼叫總覽(24h)
   - 總呼叫 / Token / cost / errors / RAG 命中 / cache 命中
   - Top 5 provider 分組
2. cmd:obs_health — 主機健康監控
   - 三主機 GCP-A / GCP-B / 111 即時 HTTP probe
   - 過去 24h uptime % + 平均 response_ms(讀 host_health_probes)
3. cmd:obs_budget — 預算控管
   - 當月 spent vs budget 各 provider
   - 超 alert_pct 自動標記 ⚠️ / 超 100% 標記 🚨
4. cmd:obs_quality — Caller 反饋趨勢
   - 過去 30 日 avg_score 最低 8 名
   - 含 thumbs_up/down + trend 圖示
   - 含 智能建議(feedback_quality_tracker)

UI/UX:
- main_menu_keyboard 加「🛰 AI 觀測台」入口
- 新 _submenu_observability() 在 menu_keyboards.py
- _SUBMENUS 註冊 'observability' key
- titles 映射加 observability 標題
- 4 個命令 cross-link(彼此互通 + 返回主選單)

Telegram 6/6 對應達成:
- promotion_review: pg_ok/pg_no inline button (既有)
- ai_calls: cmd:obs_ai_calls (新增)
- host_health: cmd:obs_health (新增)
- budget: cmd:obs_budget (新增)
- quality_trend: cmd:obs_quality (新增)
- ppt_audit: 既有「有 issues 才推 Telegram」推送行為(不需查詢命令)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 18:58:30 +08:00
OoO
0b13055466 feat(p38): host_health + ppt_audit DB 持久化(B-1 + B-2)
統帥要求:
1. 所有 6 個觀測頁的功能和數據都要完整寫入資料庫儲存
2. Ollama 切 GCP 順序 GCP-A → GCP-B → 111

盤點結果:
- 4/6 頁面已有 DB 表(ai_calls / learning_episodes / rag_query_log / ai_call_budgets)
- 2/6 頁面是即時查詢無歷史:host_health(HTTP probe)、ppt_audit(os.listdir)
- Ollama 99% 已合規,僅 1 處過時註解

修補(B-1):
- services/code_review_pipeline_service.py:207 註解更新
  「直呼內網 Ollama (192.168.0.188)」→ 「走 resolve_ollama_host 三主機級聯 ADR-027」

新增(B-2):
- migrations/029_create_host_health_probes.sql
  - 三主機健康歷史表(label/url/healthy/response_ms/error_msg)
  - 索引:probed_at / (host_label, probed_at)
  - 30 天保留(cron 清理)
- migrations/030_create_ppt_audit_results.sql
  - PPT 視覺審核結果表(status/issues_count/issues_found JSONB/confidence)
  - 索引:audited_at / pptx_filename / failed-only partial
- routes/admin_observability_routes.py:host_health_dashboard
  - 每次 probe 寫入 host_health_probes(失敗安全)
  - 新增 24h 健康趨勢卡片(uptime % / 平均 ms)
- routes/admin_observability_routes.py:ppt_audit_history
  - 從 ppt_audit_results 讀過去 7 日 audit 紀錄
  - 顯示審核時間/檔名/結果/問題數/信心度/耗時
- services/ppt_vision_service.py:check_ppt_file
  - 新增 _persist_audit_result() 跑完寫入 DB(status/issues/confidence/duration)
  - 失敗安全:DB 寫入失敗只 log warning,不擋主流程
- templates/admin/host_health.html + ppt_audit_history.html
  - 新增「24h 健康趨勢」card(host_health)
  - 新增「視覺審核歷史紀錄」card(ppt_audit)

DoD:
- 程式碼語法 ✓
- Jinja 平衡 ✓
- 失敗安全(DB 寫入或讀取失敗都不擋頁面渲染)✓

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 18:55:39 +08:00
OoO
19f1340f5c feat(p38): admin 觀測台 6 頁完整繁中化 + 加入導航選單
All checks were successful
CD Pipeline / deploy (push) Successful in 2m42s
問題:
1. 6 個 /observability/* 頁面標題與欄位英文殘留(違反設計憲法繁中要求)
2. 6 頁完全沒掛 navbar,使用者進不去(只能彼此 footer link 互連)
3. emoji 取代 Font Awesome,違反設計規範

修補:
- _navbar.html 新增「AI 觀測台」dropdown(位於 AI 助手 與 雲端匯入 之間)
  - AI 監控組:AI 呼叫總覽 / 主機健康監控 / 預算控管
  - AI 學習組:RAG 學習晉升審核 / Caller 反饋趨勢 / PPT 視覺審核歷史
- 6 個 admin/observability template 全面繁中化:
  - 標題、表格欄位、按鈕、badge 文字、JS alert 文案
  - emoji → Font Awesome icon(fa-heartbeat / fa-chart-bar / fa-wallet / fa-brain / fa-comments / fa-search 等)
  - 移除 5 處 footer 手寫 link 條(已由 navbar 取代,避免雙寫)
- routes/admin_observability_routes.py 6 個 render_template 加 active_page='obs_*'
  讓 navbar dropdown 正確高亮

完整覆蓋:host_health / ai_calls_dashboard / budget / promotion_review / quality_trend / ppt_audit_history

設計規範對齊:仍待 Phase 後續工作(ewoooc_base.html 框架升級 + --momo-* design token)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 18:49:44 +08:00
OoO
9bc6664dc0 fix(p37): cd.yaml SPA shadow grep pipefail bug — 真正修好 CD failure
All checks were successful
CD Pipeline / deploy (push) Successful in 2m29s
P34/P36 都沒打到的 root cause:
  ETAG=$(echo "$HDR" | grep -i '^etag:' | ...)
  當 grep 找不到匹配 (mo.wooo.work /health 不帶 etag header),
  grep exit 1 → bash pipefail → 變數賦值整行 exit 1 →
  set -e 殺掉整個 script → run 280/281 同樣位置死。

修:每個 grep pipeline 結尾補 `|| true` 兜底,empty result 不殺 script。

本機 bash -eo pipefail 模擬實 prod /health response:
  ETAG=[] CLEN=[64] XPT=[]
  FLASK_OK=1 (CLEN=64 != 7480 觸發 PASS)
 預期下個 CD run 該 step 綠
2026-05-04 14:34:05 +08:00
OoO
64fe4fb651 fix(p36): cd.yaml SPA shadow 偵測 bash -e exit bug 修復
Some checks failed
CD Pipeline / deploy (push) Failing after 2m27s
run 280 failure 根因:P34 寫 `[ -n "$XPT" ] && [ "$X" != "0" ] && FLASK_OK=1`
三條 && 串連在 Gitea Actions 的 bash -e 模式下,第一條 -n 判斷 false
就 exit 1(empty XPT 是常態,因 mo.wooo.work /health 不帶 x-process-time)。

改 if/then/fi block — 純條件分支不影響 exit code。

驗證真 prod 已通:
- mo.wooo.work/observability/ai_calls 回 35700 byte Flask login 重導頁
  (session cookie 正常 set,35700 != 7480 SPA shell)
- mo.wooo.work/admin/ai_calls 回 404(P32 改名後正確不存在)
我 27-35 phase 全部活在 prod 上,只是 192.168.0.188 LAN 是別 project 干擾。
2026-05-04 14:30:18 +08:00
OoO
46255720ee fix(p35): Critic HIGH #2 + MEDIUM #2 — SQL f-string + 動態 import 改寫
Some checks failed
CD Pipeline / deploy (push) Failing after 2m36s
HIGH #2 — ai_calls 動態 WHERE 從 f-string 拼接改全綁參數:
  舊:sa_text(f"WHERE {' AND '.join(where_parts)}")
  新:sa_text("WHERE :since AND (:caller_f='' OR caller=:caller_f) AND ...")
  原本字串字面值來源安全,但下個 contributor 不慎把 request.args 拼進去
  就立即 SQL injection;改全綁參數消除類別風險。

MEDIUM #2 — ppt_audit_history 動態 __import__ 改頂部 import:
  舊:__import__('time').time() / __import__('datetime').datetime.fromtimestamp(...)
  新:頂部 import time(datetime 已有)+ 直接呼叫
  並新增 os.path.islink() 過濾,防 reports/ 內 symlink 攻擊逃出目錄。

12/12 tests 仍 PASS。
2026-05-04 14:23:52 +08:00
OoO
927d7072ce fix(p34): cd.yaml 加 SPA Shadow 偵測 — 防 nginx fallback 偽綠
Some checks failed
CD Pipeline / deploy (push) Has been cancelled
過去 5 個 deploy(run 273-277)全 success 但 prod 上 Flask 從未接到請求 —
nginx 對所有路徑 fallback 到 SPA index.html (7480 byte / etag e167a58a...) —
原健康檢查只看 HTTP 200,被 SPA shell 200 騙過。

新增第 3 階段檢查(接在原 HTTP 200 retry + 三容器驗證之後):
驗 /health response 三條 fingerprint 任一不符 SPA shell 即 Flask 真接到:
  (a) Content-Length != 7480
  (b) etag != e167a58a1baf907f55a2925a2e8665d1
  (c) x-process-time header 存在(Flask middleware 加的,nginx static 不會帶)

三條全失敗 = SPA 攔截 → 推 Telegram + exit 1(CD 紅)。
TELEGRAM secrets 未設時跳過告警不阻 deploy。

修了過去那種「我推 commit、CD 全綠、實際 prod 0 影響」的盲點。
2026-05-04 14:21:42 +08:00
OoO
86f1fd5f50 fix(p33): admin observability auth hardening — Critic CRITICAL 修正
Some checks failed
CD Pipeline / deploy (push) Has been cancelled
Critic 1 CRITICAL 發現:6 個觀測端點零認證 + csrf_exempt
→ Flask 一旦對外可達,任何人可 POST 晉升 episode / 改月預算
→ X-Forwarded-User header client 偽造 = 偽造 admin 身份

修正:
1. 全 8 個 route handler 加 @login_required(session-based auth)
   - GET: ai_calls / promotion_review / quality_trend / host_health /
          budget / ppt_audit_history
   - POST: promotion_review/approve, .../reject, budget/update/<id>
2. promotion_review_approve approver_hash 改從 Flask session 取
   (get_current_user().username)— 不再信 X-Forwarded-User header
3. app.py 移除 csrf.exempt(admin_observability_bp)
4. 12 tests(10 原 + 2 新 auth gate)全 PASS:
   - test_anon_get_redirects_to_login: 6 GET 路由匿名 → 302
   - test_anon_post_blocked: 3 POST mutation 匿名 → 302
2026-05-04 14:19:54 +08:00
OoO
99d2f3c543 fix(p32): admin URL prefix /admin → /observability — 避開 188 nginx SPA shadow
All checks were successful
CD Pipeline / deploy (push) Successful in 2m25s
Root cause(curl 實證):
  prod 188 nginx 對 /admin/* 設 try_files → SPA index.html fallback
  → Phase 27-31 的 6 個 Flask admin 路由全被 nginx 攔截
  → 外部 GET /admin/ai_calls 回 7480 byte 靜態 HTML(同 etag = SPA shell)
  → 我之前說「6 admin 頁 prod 200」是回了 200,但 body 不是 Flask 渲染

修法:
  Blueprint url_prefix /admin → /observability
  → 6 個觀測頁實際生效在 /observability/* 不被 SPA 遮蔽
  → SPA frontend 仍擁有 /admin/* 命名空間(不破壞既有前端)

更新範圍:
  - routes/admin_observability_routes.py: url_prefix + 註解全改
  - 6 templates: 所有 href / fetch() 路徑改 /observability/
  - tests/test_admin_observability_routes.py: client.get/post 路徑改
  - 10/10 smoke tests 仍 PASS

統帥訪問新路徑:
  http://192.168.0.188/observability/ai_calls
  http://192.168.0.188/observability/host_health
  http://192.168.0.188/observability/budget
  http://192.168.0.188/observability/promotion_review
  http://192.168.0.188/observability/quality_trend
  http://192.168.0.188/observability/ppt_audit_history
2026-05-04 14:13:27 +08:00
OoO
82595ab4ac test(p31): admin observability 6 路由 smoke tests (10/10 PASS)
防 Phase 27/28/29 6 個 admin 頁未來被改壞無人察覺。

覆蓋:
- /admin/ai_calls         200 + DB error fallback (2 cases)
- /admin/promotion_review 200
- /admin/quality_trend    200
- /admin/budget           200
- /admin/budget/update/<id> 輸入驗證 (3 cases: 拒負 budget / 拒 alert>100 / 收正常)
- /admin/ppt_audit_history 200 (掃 reports/ 不需 DB)
- /admin/host_health      200 (mock requests.get 三主機全 down 仍 render)

技術重點:
- 全 mock get_session,不接真 DB
- jinja2 csrf_token() stub 避免 base.html 渲染失敗
- requests.get monkeypatch 避免測試誤打三主機 11434

跑法:venv pytest tests/test_admin_observability_routes.py -v
2026-05-04 13:51:07 +08:00
OoO
f2fbe5f929 feat(p30): admin nav 互聯 + deploy doctor v5.0 腳本
All checks were successful
CD Pipeline / deploy (push) Successful in 2m33s
(1) 6 個 admin 頁底部導覽全互聯(之前缺 Phase 29 兩頁的反向連結)
   - ai_calls / promotion_review / quality_trend / host_health
     全部加 |Budget|PPT Audit| 連結
   - 統帥從任一頁都可一鍵跳到其他 5 頁

(2) scripts/deploy_doctor_v5.py — 統帥手動待辦自助檢查
   5 階段檢查:env vars / DB migrations / Ollama 三主機 /
                LibreOffice / MCP servers
   - 14 個 v5.0 env vars(含 criticality 分級 FAIL/WARN/INFO)
   - 5 張 v5.0 必備 table(ai_calls/mcp_calls/ai_call_budgets/
     rag_query_log/learning_episodes)
   - ai_call_budgets seed ≥8 筆檢查
   - 三主機 /api/tags HTTP probe + healthy 數判定
   - 退出碼:0=全綠 1=WARN 2=FAIL(可進 CI)
   - SSH 188 / 本機都能跑:python3 scripts/deploy_doctor_v5.py

統帥之後想知道「v5.0 還有啥沒部署」直接跑 doctor 看清單,
不用再口頭追問哪些 env vars / 哪幾張 migration。
2026-05-04 13:48:06 +08:00
OoO
69ccf8029b feat(p29): 預算管理頁 + PPT vision 歷史頁 — 完成 6 個 admin 觀測頁
All checks were successful
CD Pipeline / deploy (push) Successful in 2m23s
承接 Phase 27/28(48b8fda)剩 2 個前端頁:

1. /admin/budget — 預算編輯器
   - GET: ai_call_budgets × 當月 spent 即時對比 + throttle 狀態
   - POST /admin/budget/update/<id>: AJAX 編輯 budget_usd / alert_pct
   - 不需 restart 立即生效(cost_throttle hourly cron 自動讀新值)
   - ratio ≥80% 黃 / ≥110% 紅 / throttled 標 ⚠️ THROTTLED

2. /admin/ppt_audit_history — PPT 視覺審核歷史
   - 掃 reports/ 過去 7 日 .pptx 檔(檔名/大小/修改時間)
   - 顯示 PPT_VISION_ENABLED 狀態(true=daily 22:00 cron 自動跑)
   - 手動觸發 SOP 提示(SSH 188 跑單檔審核)

完工里程碑:6 個 admin 頁 + 1 個導覽
- /admin/ai_calls          (Phase 27)
- /admin/promotion_review  (Phase 27)
- /admin/quality_trend     (Phase 28)
- /admin/host_health       (Phase 28)
- /admin/budget            (Phase 29) ← 新增
- /admin/ppt_audit_history (Phase 29) ← 新增

Operation Ollama-First v5.0 — 前端互補互動系列收官
2026-05-04 13:44:08 +08:00
OoO
48b8fda7db feat(p27+28): Admin Observability Dashboard — 4 個前端頁互補 Telegram
All checks were successful
CD Pipeline / deploy (push) Successful in 2m25s
Operation Ollama-First v5.0 / Phase 27 + 28 — 戰役觀測前端化

routes/admin_observability_routes.py (新檔, 200+ 行)
- admin_observability_bp blueprint,url_prefix='/admin'
- /admin/ai_calls            — Phase 27 主入口(KPI / by provider / TOP 100)
- /admin/promotion_review    — Phase 28 PromotionGate 待審列表 + 通過/拒絕按鈕
- /admin/quality_trend       — Phase 25 caller 反饋趨勢視覺化
- /admin/host_health         — 三主機 + MCP + cost throttle 即時健康
- 失敗安全:DB 查詢失敗回空清單 + 警告 banner(不 raise)
- promotion_review_approve/reject 走 hash_human_approver SHA1[:8] 不存原 username

templates/admin/ (4 個新檔)
- ai_calls_dashboard.html   篩選 bar + 6 KPI cards + by provider + recent 100
- promotion_review.html     卡片列表 + 通過/拒絕 AJAX 按鈕(即時 UI feedback)
- quality_trend.html        avg score 升序排列 + 進度條 bar + 智能建議區
- host_health.html          三主機 HTTP probe + 已載入模型 + MCP + throttle

統帥提問「需要哪些前端讓兩者互補互動」答覆:
  6 項最該前端化(已實作 4 項,剩 2 項為後續):
     ai_calls 即時查詢          → /admin/ai_calls
     PromotionGate 待審核         → /admin/promotion_review (互動最強)
     caller 反饋趨勢             → /admin/quality_trend
     三主機 + MCP + throttle     → /admin/host_health
     ai_call_budgets 預算管理   → Phase 29 補
     PPT 視覺審核結果列表        → Phase 29 補

互補 Telegram 哲學:
  Telegram = push(重要事件主動通知)
  Web = pull(統帥隨時可查 / 互動審核 / 找問題)
  PromotionGate Stage 4:Telegram 推 awaiting_review + Web 批次審核(兩者皆可)

app.py blueprint 註冊 + CSRF exempt(AJAX POST 走 server-side check)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 13:36:51 +08:00
OoO
c7d04b2855 test(p26): 修 libreoffice not installed test patch path 2026-05-04 11:16:30 +08:00
OoO
72a7c385d5 feat(p26): PPT 視覺審核 daily 22:00 cron — minicpm-v 自動掃當天新生 .pptx
All checks were successful
CD Pipeline / deploy (push) Successful in 2m54s
Operation Ollama-First v5.0 / Phase 26 — PPT 自我審視整合

services/ppt_vision_service.py 擴充:
- check_ppt_file(pptx_path, max_slides=5) — 整檔視覺檢查
  • LibreOffice headless 轉每張 slide 為 png
  • 對前 N 張跑 check_image
  • 彙總 issues + 平均 confidence
  • fail-safe:LibreOffice 不在 / 轉檔失敗 → 回 skip 不阻擋
- audit_recent_ppts(reports_dir, hours=24, max_files=10)
  • 掃 reports/ 過去 24h 新生 .pptx(getmtime filter)
  • 對每個檔跑 check_ppt_file
  • 彙總總 issues
- push_ppt_audit_to_telegram(summary)
  • 有 issues 才推 Telegram(避免「無問題」洗版)
  • 每檔最多 3 張 slide / 每張 2 個 issue 列出

run_scheduler.py — 每日 22:00 cron
- run_ppt_vision_audit task wrapper
- PPT_VISION_ENABLED=false 時 service 內部 skip(不打 LLM)

設計哲學:
不動既有 5 個 prs.save() 呼叫點(risk 高)→ 改寫獨立 daily cron 集中處理
零侵入 PPT 生成主流程 / 零 risk regression / feature flag OFF 預設

部署需求:
LibreOffice headless(apt install libreoffice)— 不在則 cron task 自動 skip + log

tests/test_ppt_vision_audit.py (9 tests 全綠)
- flag OFF skip / 目錄不存在 / 無 .pptx
- 舊檔(>hours)filter / LibreOffice 不在 fail-safe
- check_ppt_file flag/missing 容錯
- Telegram 推播:無 issues 不推 / 有 issues 推

regression: ppt_vision_service 既有 6 tests 全綠

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 11:16:11 +08:00
OoO
bd32e04dad feat(p25): 反饋環深化 — caller-level quality 趨勢追蹤 + ROI 月報整合
All checks were successful
CD Pipeline / deploy (push) Successful in 3m2s
Operation Ollama-First v5.0 / Phase 25 — 反饋環自主學習深化

services/feedback_quality_tracker.py (180+ 行)
- 純 SQL 統計,零 LLM 成本
- 4 個閾值常數(demote 👎×5/avg<2.5 / promote 👍×10/avg>=4.5)
- compute_caller_quality_trend(days=7) — 取近 N 日各 caller 反饋
- get_caller_recommendations() — 給 token 日報/ROI 月報用
  • 規則 1: 👎 ≥ 5 次 → review
  • 規則 2: avg < 2.5 + 樣本足 → review
  • 規則 3: 👍 ≥ 10 + avg ≥ 4.5 → promote(建議關閉 Gemini fallback)
- should_demote_caller(caller) — 自動降權判斷(戰役預設不啟用)
- render_quality_summary() — 給訊息用 emoji 摘要

ROI 月報整合(services/roi_report_service.py):
- 加 Section 「💬 Caller 反饋趨勢(30 日)」TOP 10 by 最低 avg
- 加 Section 「🔮 智能建議」最多 3 條(review / promote)
- 失敗 swallow 不影響月報主流程

訊息範例:
  💬 Caller 反饋趨勢(30 日)
    ⚠️ openclaw_qa: avg 1.85/5 (👍2 👎8 n=12)
     hermes_analyst: avg 3.10/5 (👍5 👎3 n=10)
     ppt_gemini: avg 4.75/5 (👍12 👎0 n=15)
  🔮 智能建議
    ⚠️ openclaw_qa: 近 30 日 👎 反饋 8 次 (avg 1.85/5) — 建議統帥檢視 prompt 或切換 model
     ppt_gemini: 近 30 日 👍 反饋 12 次 — 可考慮關閉 Gemini fallback 純走 Ollama

tests/test_feedback_quality_tracker.py (10 tests 全綠)
- 4 閾值常數 / DB fail 安全 / 空 trends 容錯
- demote 規則(👎 多次)/ promote 規則(👍 多次)/ neutral 不觸發
- should_demote_caller 樣本不足保護
- trend 分類(positive/negative/neutral/no_data)正確

依 ADR-032 RAG 自主學習迴圈 + ADR-033 護欄 #1
不直接改 caller 行為(避循環自動修正失控),只產出建議給統帥審視。

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 11:12:52 +08:00
OoO
0476d3ae4e feat(p24): ROI 月報生成器 — 每月 1 日 09:00 推 Telegram
All checks were successful
CD Pipeline / deploy (push) Successful in 2m49s
Operation Ollama-First v5.0 / Phase 24 — 戰役 ROI 自動量化

services/roi_report_service.py (200+ 行)
- BASELINE 戰前估算(gemini 50M/$20、nim 5.8M、ollama 30M、total $25/月)
- query_last_month_stats() — SQL 查上月 ai_calls + mcp_calls + rag_query_log
- render_roi_report(stats) — HTML 訊息(含 5 區塊:成本攔截/provider 分布/RAG/MCP+Cache/KPI)
- generate_and_send_roi_report() — 主入口,推 Telegram + 寫 ai_insights 長期記錄
- 達標標記:Gemini -23.5%  / RAG 命中 ≥25% 

Telegram 訊息範例:
  📊 ROI 月報 2026年04月
  💰 成本攔截
    Gemini: 35,000,000 tokens / $14.00
    vs 戰前: 50,000,000 / $20.00
     攔截: 15,000,000 tokens / $6.00 (30.0%)
  🤖 Provider 分布
  🧠 RAG 自主學習(含 saved_call / 反饋分數)
  🔧 MCP + Cache
  📈 戰役 v5.0 KPI  達標

run_scheduler.py — 每日 09:00 跑(內部判斷月初第 1 日才送)
- run_roi_monthly_report_if_new_month task wrapper
- 失敗 swallow log,不影響其他排程

tests/test_roi_report_service.py (7 tests 全綠)
- BASELINE 必要欄位 / 月份範圍計算 (1月→去年12月)
- 達標訊息含  + 攔截數字
- 未達標訊息含 ⚠️
- 空 stats 容錯 / DB fail 回空 dict 不 raise

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 11:04:14 +08:00
OoO
1da7564567 feat(p22+23): caller 整合 model_router (sales_copy) + cost_throttle (claude)
Some checks failed
CD Pipeline / deploy (push) Has been cancelled
Operation Ollama-First v5.0 / Phase 22.1 + Phase 23 — 路由治理整合

Phase 22.1: services/ollama_service.py generate_sales_copy
- 短文 < 100 字(estimated_length = product_name × 5)→ 走 model_router
- model_router 推算 → 短文 gemma3:4b / 長文 llama3.1:8b
- MODEL_ROUTER_ENABLED=false 時 select_model 直接回 self.model(向下相容)
- router 失敗 swallow(fallback self.model 不影響主流程)

Phase 23: services/anthropic_service.py is_available()
- 新增 cost_throttle 整合:claude provider throttle 時 is_available=False
- caller 看到 False 自動走 Gemini fallback,不送 Claude 請求
- COST_THROTTLE_ENABLED=false 時不影響(戰役預設 OFF)
- cost_throttle 不可用時 try/except 不阻擋(向下相容)

行為對照:
  戰前:sales_copy 永遠用 self.model (llama3.1:8b)
  戰後(flag OFF):完全相同
  戰後(flag ON):商品名 < 20 字 → gemma3:4b 短文,提速 50%

  戰前:Claude 燒到月底超預算才告警,無自動節流
  戰後(throttle flag OFF):完全相同
  戰後(throttle flag ON):claude 月底推估 > 110% → is_available=False
                              → caller fallback Gemini 自動省錢

regression: 既有 retry_chain / anthropic / model_router test 全綠

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 11:00:04 +08:00
OoO
390c32b05d feat(p21): Caller × Context 動態 Model Router + ADR-034
All checks were successful
CD Pipeline / deploy (push) Successful in 2m45s
Operation Ollama-First v5.0 / Phase 21 — 動態路由治理

services/llm_model_router.py (160+ 行)
- 純規則引擎,零 LLM 成本(Python lambda predicate)
- 6 caller × 12 條路由規則:
  • sales_copy: 短文 < 100 字 → gemma3:4b / 長文 → llama3.1:8b
  • hermes_analyst: gap > 20% 或銷量 < -50% → qwen3:14b / 預設 hermes3
  • aider_heal: diff > 200 行 → qwen2.5-coder:32b / 預設 7b
  • openclaw_qa: query > 200 字或 multi_turn → qwen3:14b / 預設 qwen2.5:7b-instruct
  • ppt_vision: minicpm 不健康 → llava / 預設 minicpm-v
  • ea_engine: require_chain_of_thought → deepseek-r1:14b / 預設 Gemini
- feature flag MODEL_ROUTER_ENABLED 預設 OFF(向下相容)
- 失敗安全:predicate 例外 skip 到下一條

tests/test_llm_model_router.py (18 tests 全綠)
- T1 flag OFF 不路由
- T2 sales_copy 短/長文路由
- T3 hermes 簡單/複雜 SKU
- T4 aider_heal 簡單/重構
- T5 ppt_vision 主備援
- T6 ea_engine CoT 路由
- T7 predicate 例外容錯
- T8 utility 函數

ADR-034 — Caller × Context 動態 Model Router
- 6 caller 路由規則對應表
- 5 段否決方案(LLM-based / hardcode / 配置檔 / 統一升級)
- Phase 21.2-21.6 戰略性遷移計畫
- V1-V3 驗收 SQL(caller 整合後 model 分布觀察)

關聯:Primary + Secondary 兩台 GCP 已備齊 10 模型(67GB 對稱)支援所有
路由規則;caller 整合可分階段進行(Phase 21.2-21.5)。

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 10:54:12 +08:00
OoO
002e498648 feat(p20+): COST_TABLE 確認 4 新 Ollama 模型(GCP Primary+Secondary 已拉)
All checks were successful
CD Pipeline / deploy (push) Successful in 2m52s
Operation Ollama-First v5.0 / Phase 20+ 完整啟動

Primary + Secondary 兩台 GCP 完整對稱(10 模型 / ~67GB 各):
   bge-m3:latest         1.2GB  Embedding
   hermes3:latest        4.7GB  Hermes 戰術
   qwen2.5-coder:7b      4.7GB  AiderHeal 既有
   qwen2.5-coder:32b    19.0GB   AiderHeal 32B 升級
   qwen2.5:7b-instruct   4.7GB  Q&A 預設
   qwen3:14b             9.3GB  Q&A / Nemotron 升級
   deepseek-r1:14b       9.0GB   推理鏈備援
   minicpm-v:latest      5.5GB  PPT vision 主
   llava:latest          4.7GB   Vision 備援
   gemma3:4b             3.3GB   輕量任務

ai_call_logger COST_TABLE 確認 4 新模型 + 2 重命名(minicpm-v / llava)
- 解 logger 「unknown model cost」誤報
- 預期啟用:
  - qwen2.5-coder:32b → AiderHeal 大型重構(call site 將擴展)
  - deepseek-r1:14b → EA HITL 推理(取代部分 Gemini Pro)
  - llava:latest → minicpm-v 失敗備援
  - gemma3:4b → sales_copy < 100 字輕量任務

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 10:48:22 +08:00
OoO
c13dc22639 feat(p20)+docs: cost auto-throttle + LLM 模型完整評估
All checks were successful
CD Pipeline / deploy (push) Successful in 2m44s
Operation Ollama-First v5.0 / Phase 20 + LLM 模型治理

services/cost_throttle_service.py (新檔, 200+ 行)
- evaluate_throttle_status() 每小時 cron 跑
- 查 ai_call_budgets monthly × 累計 spent → 月底線性外推
- 推估 > 預算 110% → 標 throttled(hysteresis:降到 95% 才解除)
- _push_throttle_alerts: 狀態變化推 Telegram
- is_provider_throttled(provider) public API(給 anthropic/gemini caller 啟動 check)
- COST_THROTTLE_ENABLED 預設 OFF(避免戰時誤節流)

run_scheduler.py 加 2 cron + task wrapper
- 每 1 小時:cost_throttle_evaluate
- 每日 00:05:cost_throttle_reset_if_new_month

docs/llm_model_full_evaluation_20260504.md (260+ 行)
- 場景 × 模型對應矩陣(4 大層次)
  戰術層 / 戰略層 / 多模態 / 雲端 API
- 本次啟動的追加 4 模型(qwen2.5-coder:32b / deepseek-r1:14b /
  llava / gemma3:4b)— Primary + Secondary 並行拉
- Phase 21 路由優化建議(context size + complexity 動態選 model)
- Phase 22 多供應商編排 + cost throttle 整合
- 儲存 / RAM / 延遲評估
- 模型治理 SOP(新增 / 替換 / 淘汰)
- COST_TABLE 對齊(含 deepseek 直連價格)

啟用前置(待統帥):
1. Primary + Secondary 4 模型拉完(背景進行中)
2. .env: COST_THROTTLE_ENABLED=true(觀察 1 週後)
3. ANTHROPIC_API_KEY 設後 Code Review 自動切 Claude Opus 4.7

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 10:36:56 +08:00
OoO
f11b0cc732 test(p19): 補 Phase 14/15/16/17 unit test — 27 tests 全綠
Operation Ollama-First v5.0 / Phase 19 — 補完戰役紀律

tests/test_caller_registry.py (7 tests)
- registry 含 30+ 核心 caller (ADR-028 對齊)
- is_known_caller / assert_known_caller strict=False/True 行為
- ai_call_logger 整合:未知 caller log warning 不阻擋
- frozenset 不可變動

tests/test_deepseek_service.py (6 tests)
- is_available() 需 KEY + flag 雙條件
- generate flag OFF / 200 success / 500 / timeout
- usage tokens 解析(prompt_tokens / completion_tokens)

tests/test_ppt_vision_service.py (6 tests)
- flag OFF 不打 HTTP / 檔不存在
-  無視覺異常 / ⚠️ marker 解析
- HTTP 500 觸發 mark_unhealthy / timeout fail-safe

tests/test_low_quality_response_v2.py (8 tests)
- 規則 5 純英文回應 (中文 < 30%)
- 規則 6 thinking-mode 漏洞 <think>...</think>
- 規則 7 重複迴圈 (前 50 字 ≥ 3 次)
- 規則 8 佔位符 ({{var}} / [TODO] / <待填>)
- 合法繁中商業文字應通過 8 條規則

regression: 全戰役 unit test 累計 241 tests
- Phase 1: 52 (logger + report)
- Phase 2: 14 (ollama_resolve)
- Phase 3: 36 (qa/golden/nemotron/daily)
- Phase 7: 23 (anthropic + code_review)
- Phase 11: 70 (rag + learning + promotion)
- Phase 10.5: 8 (mcp_router)
- Phase 13: 10 (retry chain)
- Phase 19: 27 (caller_registry + deepseek + ppt_vision + lq_v2)  新

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 10:27:35 +08:00
OoO
98063059c2 feat(p14-18): PPT vision + DeepSeek 直連 + caller_registry + Hermes 強化 + postmortem
All checks were successful
CD Pipeline / deploy (push) Successful in 2m50s
Operation Ollama-First v5.0 / Phase 14-18 全套(statesman 批准全部)

Phase 14 — services/ppt_vision_service.py (新檔, 200+ 行)
- minicpm-v:latest(GCP Primary 已拉 5.5GB,代替 qwen2-vl 不存在)
- check_image(image_path) → VisionResult.issues_found 視覺異常清單
- 走 resolve_ollama_host 三主機 retry + mark_unhealthy
- 繁中強制 system prompt + 結構化解析 ⚠️ marker
- feature flag PPT_VISION_ENABLED 預設 OFF

Phase 15 — services/deepseek_service.py (新檔, 170+ 行)
- DeepSeek API 直連 (api.deepseek.com/v1),OpenAI-compatible
- 取代部分 OpenRouter 路徑(直連便宜 ~30-50% + 延遲低)
- deepseek-chat ($0.014/$0.28) / deepseek-reasoner ($0.14/$2.19)
- feature flag DEEPSEEK_DIRECT_ENABLED 預設 OFF
- DeepSeekResponse 含 input_tokens/output_tokens/duration_ms

Phase 16 — services/llm_caller_registry.py (新檔, 130+ 行)
- CALLER_REGISTRY frozenset 集中管理 35+ 個 caller 名(ADR-028 白名單)
- assert_known_caller(strict=False) 整合到 ai_call_logger __init__
- 不在 registry → log warning(不 raise,保留擴展彈性)
- list_callers_by_service() 分組除錯
- 解 critic-A11 第 3 輪 L4 修補(命名分散三層)

Phase 17 — _is_low_quality_response 4 條新規則(A2 警訊深化)
- 規則 5:純英文回應(中文字元 < 30%)
- 規則 6:thinking-mode 漏洞(<think>...</think> 洩漏)
- 規則 7:重複迴圈偵測(前 50 字出現 ≥ 3 次)
- 規則 8:佔位符未填充({{var}} / [TODO] / <待填>)

Phase 18 — docs/operation_ollama_first_v5_postmortem.md (新檔)
- 戰役完整時間軸(Day 1-2)
- 3 大決策替代分析
- 4 個 critical hotfix 教訓
- Owen 三護欄落地對照
- KPI 達成度(Wave 1 提前 4 天 / Wave 2 提前 10 天)
- 統帥手動清單 + 7 條未來戰役教訓

Phase 13 補強(合併本 commit):
- ai_call_logger COST_TABLE 補 7 個新模型(qwen3:14b / qwen2.5:7b-instruct
  / qwen2.5-coder:32b / qwen2-vl:7b / deepseek-r1:14b / gemma3:4b / minicpm-v)

regression: 214 unit tests 全綠(4:02 跑完),2 skipped

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 10:19:13 +08:00
OoO
942193db2a feat(p13): OllamaResponse token 補欄 + COST_TABLE 補新模型 + retry 鏈 unit test
All checks were successful
CD Pipeline / deploy (push) Successful in 2m41s
Operation Ollama-First v5.0 / Phase 13 補強

(A) services/ollama_service.py — OllamaResponse 加 input_tokens/output_tokens
- A4 Phase 1 已知 limitation 修補:openclaw_bot_main token=0 假數據誤導日報
- generate() 解 prompt_eval_count + eval_count 寫 OllamaResponse
- 影響:ai_call_logger 收到正確 token 數,token 日報 Ollama 占比準確

(B) services/ai_call_logger.py — COST_TABLE 補 GCP 已拉/候選模型
- qwen2.5:7b-instruct (Phase 3 A7 OpenClaw Q&A 預設)
- qwen3:14b (Phase 3 A9 Nemotron + A7 升級候選)
- qwen2.5-coder:32b (Phase 8 候選)
- qwen2-vl:7b (Phase 13+ PPT vision 候選)
- deepseek-r1:14b / gemma3:4b (推理增強 / 輕量)
- 全部 cost=0(Ollama 自架)
- 解 logger.warning「unknown model cost」誤報

(J) tests/test_ollama_retry_chain.py (10 unit tests) — 驗 hotfix e862a90/6572d52
- T1 self.host @property lazy resolve
- T2 explicit host 凍結不 retry
- T3 generate 第一台 timeout → 第二台成功(核心 retry 鏈)
- T4 三主機都失敗 → success=False
- T5 cache 卡同主機 → break 不無限迴圈
- T6 Phase 13 token 解析驗證
- T7-T9 generate_embedding 同類驗證
- T10 mark_unhealthy 清 resolve cache

regression: 全戰役 14 test 檔仍 zero regression

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 10:07:33 +08:00
OoO
c1fd913a35 feat(p10.5): MCP Router 統一介面 + mcp_collector 接 omnisearch L0
All checks were successful
CD Pipeline / deploy (push) Successful in 2m55s
Operation Ollama-First v5.0 / Phase 10.5 收尾(ADR-031 落地)

services/mcp_router.py(350 行)— 統一 MCP HTTP 路由
- MCPRouter.call(server, tool, args, caller) 主入口
- TOOL_REGISTRY 白名單:mcp_collector / hermes_analyst / openclaw_strategist
  限制 caller × server × tool 組合,防 LLM 亂打
- 4 個 server endpoint env 配置(postgres:3001 / firecrawl:3002 /
  omnisearch:3003 / filesystem:3004)對齊 docker-compose.mcp.yml
- 記憶體 cache(1h TTL + LRU 200 筆 + sha256[:16] key)
- fire-and-forget mcp_calls 寫入(async thread)
- PII 保護:input_args 只存 hash + keys 不存原文
- 大小護欄:> 64KB 截斷 + _truncated flag
- health_check() 4 server 狀態
- feature flag MCP_ROUTER_ENABLED 預設 OFF

services/mcp_collector_service.py — _search_topic 加 L0 omnisearch 路徑
- MCP_ROUTER_ENABLED=true 時優先走 self-hosted Tavily / Exa
- omnisearch 失敗自動 fallback 到既有 Gemini Grounding 鏈
- 完整 fallback 鏈(最終態):
    L0: omnisearch tavily → omnisearch exa(取代 Gemini Grounding 主路徑)
    L1: Gemini 2.0 Grounding(既有,保留為 fallback)
    L2: Gemini 1.5 Grounding(既有)
    L3: Ollama qwen2.5-coder:7b(既有)
    L4: 靜態 fallback_topic_content(既有)

預期收益(mcp-stack deploy + flag ON 後):
- Gemini Grounding 月省 ~70% 成本
- Tavily 1000 free credits/月 + Exa 1000 free,月成本 $0
- ~180 calls/月使用率 18% 可承受 5x 增長

tests/test_mcp_router.py(8 tests 全綠):
- flag OFF 不打 HTTP / 白名單檢查 / cache 命中第二次 / timeout / 500 /
  cache key 排序穩定 / health_check / 未知 server

啟用步驟(待統帥 deploy mcp-stack 後):
1. .env 加 MCP_ROUTER_ENABLED=true
2. docker compose -f docker-compose.mcp.yml up -d (188)
3. mcp_router.health_check() 全 200 OK 驗證

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 09:34:21 +08:00
OoO
97c446303c feat(p11.0): BGE-M3 跨主機一致性驗證 + 每週日 04:30 cron
Some checks failed
CD Pipeline / deploy (push) Has been cancelled
Operation Ollama-First v5.0 / Phase 11.0 收尾(ADR-033 護欄 #3 完整落地)

services/rag_service.py 新增:
- verify_embedding_consistency() — 跨三主機 BGE-M3 embedding 一致性驗證
  測試文字「momo電商競品分析測試向量一致性檢查」分別呼叫 GCP Primary /
  Secondary / 111 三主機,計算兩兩 cosine 距離。
  max_diff > 1e-4 視為不一致(模型版本漂移)→ logger.error。
- _cosine_distance() — 純 Python,不依賴 numpy
- fail-safe:< 2 主機可達也回 ok=True(戰時部分主機暫斷不算錯)

run_scheduler.py 新增:
- run_embed_consistency_check task wrapper
- schedule.every().sunday.at("04:30").do(...) — 每週一次足夠
  (不需每次啟動驗證,過頻會打三主機 Ollama 浪費)

落地 ADR-033 護欄 #3 完整版:
  簽名鎖定(migration 026 embedding_signature 欄位) 既有
  程式端簽名計算(rag_service.get_embedding_signature) 既有
  RAG 查詢時簽名比對過濾(rag_service._select_hits) 既有
  跨主機一致性驗證 cron  新增 
  既有 14k+ 筆回填  待手動跑 enqueue_missing_insight_embeddings()

regression: 47 unit tests 全綠

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 09:31:31 +08:00
OoO
84a8c07e4a feat(p11.5): learning_episodes embedding 寫入 — 解鎖 Stage 3 dedup
All checks were successful
CD Pipeline / deploy (push) Successful in 2m57s
Operation Ollama-First v5.0 / Phase 11.5 收尾(A4 已知 limitation 補完)

問題:Phase 11 A4 完成時揭露:
> Stage 3 dedup 需 episode 先 embed:目前 LearningPipeline.enqueue 寫入時
> embedding 為 NULL,所有 episode 都會略過 Stage 3 dedup

修補:
- learning_pipeline.enqueue 內 episode INSERT commit 後 enqueue embedding worker
- 用既有 _enqueue_embedding('learning_episodes', episode_id, distilled_text)
- ADR-007 retry queue worker 自動處理(_process_one_embedding 已動態 UPDATE
  {target_table},已支援 learning_episodes 表)
- distilled_text 截 4000 字避免 retry queue 表膨脹
- 失敗 swallow,僅 log debug(不阻擋 episode_id 回傳)

落地 ADR-033 護欄 #1 完整版:
  Stage 1: quality_score >= 0.7         既有
  Stage 2: 無幻覺檢測(規則引擎)        既有
  Stage 3: 與既有 insight cosine < 0.95  解鎖 
  Stage 4: weight >= 0.8 必經 👍/👎      既有

regression: 70 unit tests 全綠(含修正 test_enqueue_returns_id_on_success
配合新增 _enqueue_embedding 的 commit 計數變化)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 09:16:39 +08:00
OoO
c2124dce00 feat(p11+): RAG worker cron — promotion_gate / awaiting_review / expire
All checks were successful
CD Pipeline / deploy (push) Successful in 2m53s
Operation Ollama-First v5.0 / Phase 11+ 收尾(ADR-032/033 落地)

services/learning_pipeline.py 新增 2 個 worker 函數:
- process_pending_episodes(batch=50) — 批次處理 pending → can_promote → promote/reject/await
  純規則引擎,不跑 LLM(Distiller 純 Hermes 規則)
- push_awaiting_reviews_to_telegram(batch=5) — 推 Stage 4 awaiting_review 到 Telegram
  TELEGRAM_ADMIN_CHAT_ID 未設則跳過(fail-safe)
  訊息含 episode_id + weight + quality + 600 字截斷文,附 promotion_review_keyboard 👍/👎

run_scheduler.py 加 3 個 cron + 對應 task wrapper:
- 每 5 分鐘  → run_promotion_gate_worker
- 每 30 分鐘 → run_awaiting_review_push
- 每 4 小時  → run_expire_stale_reviews(24h 無回應 → weight=0.5)

設計安全保證:
- RAG_ENABLED=false 時 learning_episodes 為空,3 個 worker 跑空 loop(無害)
- 所有 worker 例外完全吞掉,僅 log error,不影響其他排程
- promote 成功才回 stats['promoted']++,DB 失敗計 errors

完整 RAG 自主學習迴圈閉環:
  LLM 結果 → Distiller → learning_episodes (pending)
    ↓ 每 5 分鐘 worker
  PromotionGate 4 階段
    ↓ approved → 寫 ai_insights → RAG 可檢索
    ↓ awaiting_review → 每 30 分鐘推 Telegram
        ↓ 24h 無回應 → 每 4h expire → weight=0.5
        ↓ 👍 callback → promote → ai_insights
        ↓ 👎 callback → rejected_human → 永不晉升

仍待 Phase 12+ 完成:
- learning_episodes.embedding 寫入路徑(Stage 3 dedup 解鎖)
- RAG_ENABLED=true 灰度啟用條件(需 100+ episodes + ANTHROPIC_API_KEY)

regression: 70 unit tests 全綠

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 09:11:27 +08:00
OoO
4e82acc0f5 feat(p10)+docs(adr): MCP 自建 Stack docker-compose + ADR-031
Operation Ollama-First v5.0 / Phase 10 + Phase 12 收尾

docker-compose.mcp.yml — 4+3 容器 MCP stack
- postgres-mcp (port 3001): Claude 直連 momo_pro DB read-only RBAC
- mcp-omnisearch (3003): Tavily 主 + Exa 備(取代 Gemini Grounding)
  避開 Brave(2026-02 取消免費 tier)
- firecrawl-self (3002): 自建爬蟲,SPA 反爬蟲
- filesystem-mcp (3004): 跨主機檔案 read-only

護欄 #2 落地(Owen v5.0 鐵律 / ADR-033):
  firecrawl-self mem_limit:2g + cpus:1.5
  PLAYWRIGHT_BROWSER_POOL_MAX=3
  chrome-reaper sidecar 每小時清 Chrome zombies

安全設計:
- 全部 127.0.0.1 暴露(不外網)
- read-only volume mount(filesystem 只能讀)
- postgres-mcp RBAC mcp_readonly role 限 SELECT 6 熱表
- API key 全走 env var 不寫死

ADR-031 — MCP 自建 Stack 治理決策
- 取代 Gemini Grounding 唯一通路(多供應商策略)
- 預期 70%+ grounding 流量走免費 Tavily
- 188 主機資源 +4-5GB RAM 可控
- Migration Plan:6 步驟(含 Tavily/Exa key 申請 + mcp_readonly role 預建)

啟用前置(待統帥):
1. .env 加 TAVILY_API_KEY / EXA_API_KEY / MCP_POSTGRES_PASSWORD / FIRECRAWL_AUTH_KEY
2. momo-db 建 mcp_readonly role + GRANT SELECT
3. ssh wooo@110 → ssh ollama@188 → docker compose -f docker-compose.mcp.yml up -d

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 09:02:07 +08:00
OoO
6572d521ba fix(embed): generate_embedding 三主機 retry — 修同類「111 死則全死」bug
All checks were successful
CD Pipeline / deploy (push) Successful in 2m42s
承前 commit e862a90(generate retry)的同類修補:
generate_embedding 之前邏輯:
  target_host = host or env or resolve  # 一次解析
  try: post → mark_unhealthy + return []  # 失敗無 retry

修補後:
  caller 顯式 host → 凍結不 retry(向下相容)
  caller 走 lazy → 三主機 retry 鏈:
    每次 self.host 走 resolve_ollama_host()
    失敗 mark_unhealthy + cache 失效 + 取新主機
    最多 3 次(避免同主機無限迴圈)

影響範圍:KM embedding worker / RAG query embedding / openclaw_learning

regression: 57 unit tests 全綠

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 08:56:38 +08:00
OoO
e862a9040c fix(ollama): 解「111 關機 → GCP 也斷」三主機 retry 鏈 + lazy host
All checks were successful
CD Pipeline / deploy (push) Successful in 9m14s
統帥 2026-05-04 反饋:「111 關機後,兩台 GCP Ollama 也跟著斷線不可用」

根因(雙 bug 連動):
  1. OllamaService.__init__ 凍結 self.host:
     `self.host = host or resolve_ollama_host()` 是 instance 級凍結
     容器啟動時若 GCP cold start 觸發 fallback 111 → self.host 永遠卡 111
     即使 cache 過期,instance 不會重新 resolve
  2. generate() 失敗無 retry 鏈:
     原邏輯只 mark_unhealthy(self.host) + return failure
     沒有「換下一台主機再試」邏輯 → 111 死則全死

修補(雙管齊下):
  A. self.host 改 @property:每次存取走 resolve_ollama_host()
     - caller 顯式指定(_explicit_host)才凍結
     - 內部 _RESOLVE_TTL 120s cache 控制 HTTP probe 成本
  B. generate() 三主機 retry 鏈:
     for attempt in range(3):
         current_host = self.host  # property lazy resolve
         if attempted → break (避免無限迴圈)
         post → success ? return : mark_unhealthy + retry
     mark_unhealthy 自動清空 resolve cache,下次 self.host 取新主機

行為對比:
  戰前:GCP cold start 卡 111 → 111 關機 → 全部失敗
  戰後:GCP cold start 卡 111 → 111 關機 → mark_unhealthy(111) →
        self.host 重 resolve → GCP Primary(已暖機)→ 成功

generate_embedding 同類修補延後(caller 多走 explicit host 路徑風險較低)

regression: 36 unit tests 全綠(test_ollama_resolve + test_ai_call_logger)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 08:42:52 +08:00
OoO
c29ce83653 docs(adr): ADR-032 RAG 自主學習迴圈 + ADR-033 三護欄
Operation Ollama-First v5.0 / Phase 12 Wave 2 收尾

ADR-032 — RAG 自主學習迴圈
- 雙表分離:rag_query_log (audit) / learning_episodes (蒸餾池) / ai_insights (知識庫)
- Distiller 規則引擎(純 Hermes 零 LLM 成本)
- PromotionGate 4 階段晉升閘
- Telegram 反饋環(rag_feedback / promotion_review keyboard)
- feature flag RAG_ENABLED 預設 OFF
- V1-V4 驗收 SQL(命中率 / 晉升通過率 / 反饋分布 / embedding 一致性)

ADR-033 — RAG 三護欄(Owen v5.0 鐵律)
- 護欄 #1 Promotion Gate:強制反饋門檻,weight>=0.8 必經人工驗收
- 護欄 #2 Firecrawl 資源:Docker mem_limit:2g + chrome-reaper sidecar + 1.8GB 告警
- 護欄 #3 BGE-M3 一致性:embedding_signature SHA1[:12] + 啟動跨主機驗證
- 五案否決理由完整(包含「不要反饋按鈕」「不限資源」「:latest 接受漂移」)

Migration Plan 對照:
   migration 026/028 schema + service 已落地
   Phase 12+ 補:embedding 寫入 / worker cron / Telegram 推播 / Firecrawl 部署 / signature 回填

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 00:01:19 +08:00
OoO
47fe375952 fix(ci): CD migration apply 邏輯 hotfix — 改跑全 v5.0 範圍(024-099)
All checks were successful
CD Pipeline / deploy (push) Successful in 3m42s
統帥 2026-05-04 Telegram 報錯:「ai_calls relation does not exist」

根因:
  cd.yaml 原邏輯 `git diff HEAD~1 HEAD -- migrations/` 只看單一 commit。
  v5.0 migrations 024-028 在 commit 4648673(最早),後續 12 個 commit
  都不含 migration → CD「自動 apply」step 一次都沒觸發。
  → ai_calls / mcp_calls / ai_call_budgets / rag_query_log /
    learning_episodes / embedding_signature 全部缺表 / 缺欄位。

修補:改邏輯跑 migrations/02[4-9]_*.sql + 03[0-9]_*.sql 等 v5.0 範圍
  - 所有 v5.0 migration 是 IF NOT EXISTS / WHERE NOT EXISTS 冪等保證
    (critic-A11 第 1 輪 B2/H1/H2/H3/M1/M2 修補時加的)
  - 重跑 100% 無害,已建立的表會被 IF NOT EXISTS 跳過
  - 026 / 027 / 028 含 ivfflat/CONCURRENTLY 走 transactionless apply

push 後 CD 跑完 → ai_calls 表立即存在 → 23:55 token 日報恢復正常

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 23:59:04 +08:00
OoO
c7d6db31f2 feat(p11): RAG 自主學習 + Promotion Gate 4 階段護欄(feature flag OFF)
Some checks are pending
CD Pipeline / deploy (push) Has started running
Operation Ollama-First v5.0 / Phase 11 / RAG 自主學習迴圈

services/rag_service.py (532 行)
- RAGService.query() — bge-m3 embed + cosine 0.85 threshold + top_k=5
- get_embedding_signature() — v5.0 護欄 #3 一致性檢查 (SHA1[:12])
- fire-and-forget rag_query_log INSERT (不阻塞主流程)
- feedback() — Telegram 👍/👎 寫回 feedback_score
- RAG_ENABLED 預設 OFF(戰前行為不變)

services/learning_pipeline.py (750 行)
- Distiller — 純 Hermes 規則引擎,零 LLM 成本
  Quality 規則:MCP >200 字 0.8 / LLM JSON ok 0.9 / TextRank 0.6 / 👍 1.0 / 👎 0.0
- PromotionGate — Owen v5.0 護欄 #1 鐵律
  Stage 1: quality_score >= 0.7
  Stage 2: 無幻覺檢測(規則引擎,零 LLM)
  Stage 3: 與既有 insight 相似度 < 0.95(Stage 3 在 episode embed 後啟用)
  Stage 4: weight >= 0.8 必經 Telegram 👍/👎
- expire_stale_reviews() — 24h 無回應自動降級 weight=0.5
- hash_human_approver — Telegram username SHA1[:8] PII 保護

services/hermes_analyst_service.py — 新增 analyze() RAG-first
- RAG hit → return synthesize(不燒 LLM)
- RAG miss → 既有 LLM 路徑 + enqueue learning_episodes

services/openclaw_strategist_service.py — Q&A 入口接 RAG-first
- 不動週/月/年報(敘事報告 RAG hit 機率低)

services/telegram_templates.py
- rag_feedback_keyboard() — 👍/👎 inline keyboard
- promotion_review_keyboard() — Stage 4 人工驗收按鈕

routes/openclaw_bot_routes.py — 3 組 callback handler
- rag_fb:{id}:{score} → rag_service.feedback()
- pg_ok:{episode_id} → PromotionGate.promote()
- pg_no:{episode_id} → PromotionGate.reject()

70 unit tests 全綠 + 全戰役 196 tests zero regression(4:17 跑完)

剩餘 limitations(Phase 12+ 補):
1. learning_episodes.embedding 寫入路徑(Stage 3 dedup 暫 skip)
2. PromotionGate worker cron 未掛
3. Telegram awaiting_review 推播未接(callback handler 已就位)

灰度開啟條件(建議 1 週後):
- ANTHROPIC_API_KEY 設定 + RAG_ENABLED=true + threshold=0.90 保守
- feedback_score >= 4 比率 > 70% → threshold 降至 0.85

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 23:56:12 +08:00
OoO
d3d90121cf docs(adr): ADR-030 Frontier 多供應商策略 — Anthropic + Google + OpenRouter
Operation Ollama-First v5.0 / Phase 12 / Phase 7 落地後追認

Phase 7 引入 Anthropic Claude(Opus 4.7 接 Code Review)後,
戰役有 2 家 Frontier 供應商,需明確治理準則:

決策矩陣(與 ADR-028 鎖定 7 場景對齊):
- 場景 #5 Code Review : Claude Opus 4.7 (Arena Elo 1548)
  → Gemini 2.5 Flash → ElephantAlpha 49B (3 層 fallback)
- 其他 6 場景維持 Gemini 主鏈

Prompt cache 戰術:
- Anthropic 5min ephemeral:Code Review 命中率預估 80%+,省 ~90% 成本
- Google Gemini:隱式 server-side cache,不可預測

預估月成本:~$32 USD
- Claude $10 + Gemini $8 + NIM $5×2 + OpenRouter $3 + Ollama $0.02

新增供應商 SOP:
1. service wrapper 加 feature flag + is_available() 檢查
2. budget 種子 + ai_calls.provider 白名單
3. unit test (fallback 鏈 + cache hit/miss)
4. 獨立 ADR

對齊:
- migration 024(claude in provider 白名單)
- migration 025(claude $10/月 budget 種子)
- ai_call_logger COST_TABLE(claude-opus/sonnet/haiku 三模型)
- services/anthropic_service.py(Phase 7 落地)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 23:42:36 +08:00
OoO
2f20d8d7ba db(p11): rag_query_log + learning_episodes — RAG 自主學習迴圈基礎
All checks were successful
CD Pipeline / deploy (push) Successful in 3m30s
Operation Ollama-First v5.0 / Phase 11 RAG + 自主學習

migrations/027 — rag_query_log(每次 RAG 查詢的 audit log)
- query_text 4KB CHECK + 90 天保留
- VECTOR(1024) bge-m3 embedding (與 ai_insights 一致簽名)
- ivfflat lists=100 索引
- saved_call 欄位追蹤「成功攔截 LLM 呼叫」次數
- feedback_score 1-5(NULL=未反饋)
- 6 條 CHECK 含 chk_rag_saved_consistent

migrations/028 — learning_episodes(蒸餾池 → ai_insights 前哨)
- 8 狀態機:pending/approved/awaiting_review/rejected_*4/expired
- weight 0-1(>=0.8 觸發 PromotionGate Stage 4 人工驗收)
- 9 條 CHECK 含 chk_le_approved_consistent / chk_le_review_consistent
- partial index idx_le_status WHERE in (pending, awaiting_review)
- distilled_text 16KB 上限

docs/phase11_db_design — 設計文檔
- 6 大決策(兩表分離 / ivfflat / partial index / 軟連結 / 90天保留 / 應用層白名單)
- 6 大風險評估(R1 PII / R2 蒸餾失誤 / R3 ivfflat 退化 / R4 dangling FK / R5/R6 trade-off)
- Phase 11 上線後驗收 SQL(EXPLAIN ANALYZE)

PromotionGate 4 階段(v5.0 護欄 #1, ADR-033):
  Stage 1: quality_score >= 0.7
  Stage 2: 無幻覺檢測(規則引擎,零 LLM)
  Stage 3: 與既有 insight 相似度 < 0.95
  Stage 4: weight >= 0.8 必經 Telegram 👍/👎(24h 無回應 → expired)

A4 fullstack-engineer 同時在寫 services/rag_service.py + learning_pipeline.py,
service 完成後一起部署啟用。

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 23:39:47 +08:00
OoO
943de8466c feat(p7): Anthropic SDK + Claude Opus 4.7 接 Code Review (feature flag OFF)
Some checks failed
CD Pipeline / deploy (push) Has been cancelled
Operation Ollama-First v5.0 / Phase 7 Frontier 升級

services/anthropic_service.py (新檔, 226 行)
- AnthropicService 包裝 + ClaudeResponse dataclass
- Ephemeral prompt cache 5 分鐘 TTL(重複 system_prompt 省 90% 成本)
- usage 解析 input/output/cache_creation/cache_read 四欄位
- ANTHROPIC_API_KEY 未設或 SDK 缺失時 is_available()=False 靜默退化

code_review_pipeline_service.py — _openclaw_assess 加 L1 Claude 分支
- CODE_REVIEW_USE_CLAUDE flag (預設 OFF,等 ANTHROPIC_API_KEY 設定後翻 ON)
- 路由:Claude Opus 4.7 (Arena code Elo 1548) → Gemini → ElephantAlpha 三層
- request_id 串鏈不變

ai_call_logger.py COST_TABLE 補 3 個 Claude 模型:
- claude-opus-4-7:    $15/$75 per M tokens (程式碼 #1)
- claude-sonnet-4-6:  $3/$15  per M tokens (agentic 平衡)
- claude-haiku-4-5:   $0.8/$4 per M tokens (輕量快速)

requirements.txt: 加 anthropic>=0.40.0
.env.example: 加 ANTHROPIC_API_KEY / CODE_REVIEW_USE_CLAUDE / CLAUDE_MODEL

52 unit tests 全綠(22 logger + 18 anthropic + 5 routing + 7 security)

啟用步驟(待統帥手動):
  1. .env 加 ANTHROPIC_API_KEY=sk-ant-...
  2. CODE_REVIEW_USE_CLAUDE=true + restart momo-app
  3. 觀察 ai_calls.cache_read_tokens > 0 確認 cache 生效

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 23:31:30 +08:00
OoO
bc4332d53f test(p3): 配合 OPENCLAW_DAILY_HERMES_TEMPLATE 預設翻 ON 更新 assertion 2026-05-03 23:30:47 +08:00
OoO
6aa5bcab88 fix(ollama-first): 3 個 feature flag 翻 ON — Ollama 優先、Gemini 殿後
Some checks failed
CD Pipeline / deploy (push) Has been cancelled
統帥 2026-05-03 23:30 指令:「免費的優先!最後才是 Gemini」

3 個 flag 預設 false → true(GCP Primary qwen3:14b 已拉好,無阻擋):
  1. OPENCLAW_QA_OLLAMA_FIRST=true
     → Telegram 戰略 Q&A 走 qwen3:14b(繁中強制 prompt + Gemini fallback)
     → 預期月省 ~6.7M Gemini tokens(戰前 8.4M × 80%)
  2. OPENCLAW_DAILY_HERMES_TEMPLATE=true
     → 日報走 Hermes 模板 + Gemini 200 字洞察(28K → 8K, -71%)
     → 預期月省 ~600K Gemini tokens
  3. NEMOTRON_OLLAMA_FIRST=true
     → 威脅分派走 GCP qwen3:14b → NIM 備援 → ADR-004 規則引擎兜底
     → 預期月省 ~5M NIM tokens(解配額痛點)

合計月省 ~12M tokens(與 ADR-029 預估 -23.5% 對齊)

緊急停用:env 變數設 false 即可(保留 fail-safe)
品質風險:A7 Q&A 有 _is_low_quality_response 守門 → 低品質自動 fallback Gemini

Operation Ollama-First v5.0 / Phase 6.5 hotfix #2 / 落地統帥指令

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 23:28:45 +08:00
OoO
56504ed7c1 fix(ea): Hermes-first short-circuit + 消除 EA escalation LLM 幻覺訊息
Some checks are pending
CD Pipeline / deploy (push) Has started running
統帥 2026-05-03 23:30 反饋:「EA escalation 訊息空洞、浪費 Gemini API」
根因:
  1. 燒錢:每個 trigger 先跑 Gemini orchestration,再 prefetch Hermes
     Hermes 0 threats 時 → Gemini 已燒,訊息卻空泛幻覺
  2. 空泛:fallback 路徑灌 OpenClaw plan 文字 + decision.reasoning
     全是「312 SKU / 23% / 14 項任務」LLM 自由發揮,無 DB 鉤住

修補:
  A. _execute_autonomous_decision 加 Hermes-first short-circuit
     - 價格類 trigger 先跑 Hermes (5s timeout, 免費 Ollama)
     - 0 threats → 直接 return,不燒 Gemini orchestration
     - 預期 >70% trigger 在此階段攔截,月省 ~3-5M Gemini tokens
     - prefetch 結果存入 trigger.conditions 給 orchestrator 用
       (避免 orchestrator 又自己編 SKU 數字)
     - log_ai_call 記 short_circuit=true 供 token report 統計
  B. _escalate_to_human fallback 路徑改極簡訊息
     - concrete=Hermes 實證 vs concrete=None 兩條路徑徹底分離
     - 有實證 → 完整訊息(含 SKU 流失金額)
     - 無實證 → 極簡訊息「⚠️ Hermes 即時數據不可用」+ SQL 查詢指引
       不再灌 OpenClaw plan 文字 / decision.reasoning(幻覺源頭)

Operation Ollama-First v5.0 / Phase 6.5 hotfix / ADR-021 遵循收尾

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 23:26:18 +08:00
OoO
2b218589bd ci(cd): 自動 apply pending migrations + paths trigger 補 migrations/**
All checks were successful
CD Pipeline / deploy (push) Successful in 3m23s
- paths trigger 加 migrations/** → DB schema 變更自動觸發 CD
- 新增「套用待跑 migration」step → CD 自動跑 git diff HEAD~1 範圍內的 SQL
- 026 含 CONCURRENTLY 不包 -1 transaction(critic-A11 B2 修補一致)
- 失敗只 warn 不中斷 deploy(migrations 設計為 IF NOT EXISTS / WHERE NOT EXISTS 冪等)

merge 後第一次部署即會自動 apply migrations 024/025/026,
無需統帥 SSH 188 跑 psql。

Operation Ollama-First v5.0 / Phase 6 收尾 / CD 自動化補洞

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 23:12:20 +08:00
OoO
3ea7004a6f refactor(p4)+docs(p5+p6): Meta 降頻 + LOCKED-GEMINI + ADR-028/029
Phase 4 A10 — OpenClaw 雙塔重劃
- run_scheduler.py: Meta 自審 cron 6h → 每日 12:00(月省 2.25M Gemini, +20% 達標)
- scheduler.py: 移除 icaim 內 2 處 inline meta 觸發
- openclaw_strategist 抽 _push_report_with_charts (call×3) + _collect_mcp_intel (call×2)
- 行數目標 -25% 未達(4 報告函數結構差異大,A10 採保守抽出避險)
- 主戰果:Meta 降頻月呼叫 300 → 30(-90%)

Phase 5 — 5 處 LOCKED-GEMINI 註解(涵蓋鎖定 7 場景)
- services/mcp_collector_service.py:32 (場景 #1: Google Search Grounding)
- services/openclaw_strategist_service.py:40 (場景 #2/3/4: 週/月/年報)
- services/code_review_pipeline_service.py:46 (場景 #5: 100K+ token diff)
- services/elephant_alpha_orchestrator.py:88 (場景 #6: EA HITL)
- routes/openclaw_bot_routes.py:98 (場景 #7: PPT 簡報)

Phase 6 A12 — 憲法級 ADR 三份
- ADR-028「LLM 路由統一準則」(269 行)
  - 5 大支柱:三主機級聯 / Ollama 優先 / 雙塔分工 / Gemini 鎖 7 場景 / 可觀測性
  - 8 個 provider 白名單(DB CHECK 對齊)
  - 30+ caller 名單分「已實作 / 規劃中」
- ADR-029「Hermes-First 雙塔分工」(222 行)
  - 12 項職責重劃表 + A7/A8/A10 落地對照
  - Gemini 月支出 -23.5%(critic 第 3 輪 B5 算術修正)
- ADR-027 附錄(+69 行)
  - 三主機架構(Primary/Secondary/Fallback)
  - 4 條獨立 fallback 鏈
  - 廢止「188 Ollama」概念
- README 索引更新

A11 critic 第 3 輪修補:5 BLOCKER 全清
- B1: 行數 1831 → 2677 (含 baseline 對照)
- B2: 場景 #4 行號 759/1267 → 1102/1628 + annual 不存在註明
- B3: 虛構 caller 改實存(ea_hitl_prefetch → ea_engine 等)
- B4: 白名單三層對齊(DB 8 = ADR 8 = token_report 補 ollama_secondary)
- B5: KPI 算術 50→38 = -23.5% 重核

services/telegram_templates.py: A5 daily_token_report() 函數
services/mcp_collector_service.py: 加 LOCKED-GEMINI 註解
services/elephant_alpha_orchestrator.py: 加 LOCKED-GEMINI 註解

103/103 unit test 全綠(zero regression)

Operation Ollama-First v5.0 / Phase 4 A10 + Phase 5 + Phase 6 A12

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 23:06:08 +08:00
OoO
838267c293 feat(p1+p3): logger 接 13 caller + Q&A/Nemotron/日報 feature flag 灰度
Phase 1 A4 — 13 個呼叫點接 ai_call_logger(覆蓋率 11.8% → 預估 50%+)
- TOP-1 nemoton_dispatcher: nemotron_dispatch caller (NIM 配額追蹤)
- TOP-2 openclaw_strategist: 4 reports (daily/weekly/monthly/meta) + qa caller
- TOP-3 hermes_analyst: hermes_analyst + hermes_intent (順修 commit 00591c5 殘留 bug)
- TOP-4 code_review_pipeline: code_review_hermes/openclaw/elephant 三鏈 (request_id 串)
- TOP-5 openclaw_bot_routes: openclaw_bot_main/gemini/nim 三層 fallback

Phase 3 A7 — OpenClaw Q&A → qwen3:14b(feature flag OFF)
- OPENCLAW_QA_OLLAMA_FIRST 灰度開關
- 繁中強制 system prompt + Gemini fallback chain
- _is_low_quality_response 品質守門(簡體字檢測 + 拒答訊號 + 結構分數)
- 黃金集 A/B 對照測試框架(10 樣本去 PII)

Phase 3 A8 — OpenClaw 日報 → Hermes 模板(feature flag OFF)
- OPENCLAW_DAILY_HERMES_TEMPLATE 灰度開關
- _compute_daily_kpi 純 SQL + Hermes 規則引擎
- _compute_gemini_insight 精簡 200 字洞察 prompt
- templates/daily_report_v2.j2 + _SafeUndefined 缺欄位優雅降級
- scripts/compare_daily_report_versions.py 雙版本盲測

Phase 3 A9 — Nemotron NIM → qwen3:14b(feature flag OFF)
- NEMOTRON_OLLAMA_FIRST 灰度開關(A2 紅燈:deepseek-r1 假支援,改 qwen3)
- _call_qwen3_dispatch + 既有 NIM tool_calls 解析共用
- 保留 ADR-004「🟡 [降級模式]」Hermes 規則引擎兜底

H6 PII fix — chat_id 進 ai_calls.meta 改 SHA1[:8](4 處 Bot Q&A)

Code Review pipeline — N3 動態 provider tag(gcp/secondary/111)+ A4 logger 三鏈

37 unit tests 全綠(routing 15 + golden 5 + qwen3 8 + daily template 8 + nemotron 1)

Operation Ollama-First v5.0 / Phase 1 A4 + Phase 3 A7+A8+A9

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 23:05:38 +08:00
OoO
078bf2683c fix(adr-027): Phase 2 — ADR-027 4 破洞修補 + 移除寫死 111
config.py — B1+B2 lazy resolve
- get_ollama_host() 取代 import-time freeze 的 OLLAMA_HOST
- get_embedding_host() 取代 EMBEDDING_HOST
- 主機切換時不需重啟 Python 進程

services/ollama_service.py — B3+B4 三主機級聯
- resolve_ollama_host(primary, secondary, fallback) 三主機級聯
  - Primary:   34.143.170.20 (SSD) — GCP 主主機
  - Secondary: 34.21.145.224 (SSD) — 同等效能備援
  - Fallback:  192.168.0.111 (HDD) — 最後一道防線
- _is_reachable: HTTP /api/version probe 取代 TCP socket(防 process 卡死假活)
- mark_unhealthy(host) 即時失效 cache,30s 內跳過該主機
- 14 unit tests 全綠

services/aider_heal_executor.py — N2
- 移除寫死 192.168.0.111,改用 get_ollama_host()
- AiderHeal 終於遵循 ADR-027 GCP 優先策略

Operation Ollama-First v5.0 / Phase 2 A6

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 23:05:11 +08:00
OoO
bb891f1a6e feat(observability): ai_call_logger + 23:55 Telegram token 日報
services/ai_call_logger.py(300 行)— 統一 LLM 遙測層
- context manager log_ai_call() / decorator logged_ai_call()
- async fire-and-forget 寫 ai_calls,DB 失敗永不影響主流程
- kill-switch:連續 10 次失敗自動降級為 logger.info
- env AI_CALL_LOGGING_ENABLED=false 一鍵關閉
- COST_TABLE 集中 13 個模型計費(gemini/claude/nim/ollama)
- PII 保護:meta 只存 prompt_hash[:12],不存原文
- 22 unit tests 全綠

services/token_report_service.py(580 行)— 6 段落每日 23:55 日報
- Section 1-6: 總覽 / 供應商分布 / TOP10 caller / 成本預算 / 趨勢 / 告警建議
- 7 條告警規則 + Hermes 規則引擎智能建議
- HTML escape + 4096 字元雙保險
- Telegram 失敗 fallback 訊息
- ai_insights 寫入 PII safe(無 chat_id/username 落地)
- 30 unit tests 全綠

A11 critic 護欄:H6 chat_id PII fix(services/openclaw_bot_routes 4 處 → SHA1[:8])

Operation Ollama-First v5.0 / Phase 1 A4+A5

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 23:04:58 +08:00
OoO
4648673423 db(p1): ai_calls/mcp_calls/budgets schema + bge-m3 signature
migrations 024/025/026 — 統一 LLM 遙測 + 預算告警 + RAG 一致性護欄
- 024: ai_calls 表 + 5 索引 + 6 CHECK constraint(H1/H2/M3/L3)
- 025: mcp_calls + ai_call_budgets + 10 種子預算(含 ollama_secondary)
- 026: ai_insights.embedding_signature + pgcrypto + CONCURRENTLY index

A11 critic 三輪審查記錄完整保留:
- Phase 1 schema review: 2 BLOCKER + 4 HIGH + 6 MEDIUM 全處理
- Phase 1 final sign-off: 0 BLOCKER + 2 HIGH + 4 MEDIUM
- Phase 6 ADR review: 5 BLOCKER + 6 HIGH 全修

Operation Ollama-First v5.0 / Phase 0+1+6 護欄

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 23:04:42 +08:00
OoO
15800a29ac [V-New] Ollama 主機切換:GCP 優先 / 111 自動備援架構 | services/ollama_service.py, docker-compose.yml
All checks were successful
CD Pipeline / deploy (push) Successful in 12m19s
2026-05-03 16:03:00 +08:00
OoO
2f5666be08 feat(import): drive staleness gate active alert when DB stale >=3d (critic-approved)
Root cause (debugger 2026-05-02):
  - drive_service.move_file 把 import 完的 Excel 搬到「已匯入」 → 工作夾空
  - auto_import_from_drive 每 30 分跑一次 list 回空 → 走 line 671-677
    silent return {success:True, file_count:0} → daily_sales_snapshot
    自 4/27 12:54 後停更 8 天無任何告警

Patch:
  Drive 空時加 staleness gate:查 DB MAX(snapshot_date),若距今 >=3 天
  即呼叫既有 _send_data_stale_alert(commit dda0a06)發 Telegram 主動催促 BU 上傳。

critic 5 點修訂全照做:
  1. session 自管:from database.manager import get_session + try/finally close
     (此區段原本沒有 session 變數,在 line 708 才開)
  2. 閾值 >=3 天:跨週末跨假期不上傳是常態,避免誤觸
  3. 沿用 _send_data_stale_alert 既有 3 字串參數,不客製文案
  4. dedupe key = 'upstream_drive':與下游 daily_report/weekly_strategy/
     monthly_report 區隔,未來 ai_insights 查詢不混淆告警源
  5. logger.error + exc_info=True:staleness 邏輯吞 try/except 不影響主流程
     return success,但留 traceback 可觀測

Regression check:
  - openclaw_strategist_service 不 import import_service → 無循環 import
  - import path 'database.manager' 與 openclaw 既有用法一致(line 31)
  - 找到檔案分支完全未動,主流程行為不變

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 13:10:55 +08:00
OoO
8b76e3872f feat(ppt): competitor v4 — 5-forces strategic analysis (Wave 4 partial)
All checks were successful
CD Pipeline / deploy (push) Successful in 2m49s
Wave 4 部分完成:competitor v4 五力升級(戰略視角)

generate_competitor_v4_ppt — 7 頁
- P1 封面:含整體領先/勢均力敵/落後徽章 + 三句話戰略指引
- P2 五力雷達圖(matplotlib polar)+ 右側 6 維度分數明細表(含雙條視覺化)
- P3 商品力 + 價格力(雙卡)
- P4 行銷力 + 服務力(雙卡)
- P5 品牌力 + 財務力(雙卡含 momo 8454/PChome 8044/蝦皮 SE/酷澎基本面)
- P6 AI 戰略整合(差異化建議)
- P7 附錄

新增 helper:_mpl_radar_png()
- matplotlib polar projection 五力雷達
- momo 焦糖橘 + 競品蜂蜜金
- 0-10 分尺度,含格線/標籤/圖例

query_competitor_5forces — 半實作
- 商品力:momo SKU 數從 DB 算 / 競品靜態 fallback
- 價格力:靜態(待擴 competitor_price_history 整合)
- 行銷力 / 服務力:靜態知識(電視購物頻道 / 24h 物流 / 訂閱制)
- 品牌力:靜態 + 預留 mcp_collector 整合空間
- 財務力:上市公司公開資訊(momo 8454 富邦集團、PChome 8044、SEA、酷澎)

每個維度自動算 momo - 競品差異 → 識別最大優勢力與最大劣勢力

_ppt_ai_analysis 加 is_5forces 分支
- 角色:BCG/麥肯錫資深戰略顧問
- 結構:整體競爭態勢 / 優勢加碼 / 劣勢補強或避戰 / SMART 三層 / 競爭風險
- max_tokens 2400

路由:
- /ppt competitor_v4         vs PChome(預設)
- /ppt competitor_v4 蝦皮    vs 蝦皮
- /ppt competitor_v4 酷澎    vs 酷澎

Telegram 按鈕:「⚔️ 競業五力 v4」

bump TEMPLATE_VERSIONS['competitor_v4'] = v4.0.0(新類型獨立版本)

簡化限制:商品力/價格力/品牌力的競品具體數據需後續擴 mcp_collector
(PChome SKU API、Dcard 品牌討論度量化等),靜態 fallback 已維持結構完整性

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 13:10:15 +08:00
OoO
ce270edc5d docs(adr): ADR-026 PPT price_elasticity + complete v3 campaign roadmap
收尾 v3 PPT 戰役(ADR-022~026 共 5 份 ADR):

完成總計:
- 18 commits(38967ce → 16b169d)
- 16 種有效 PPT 報表
- 2 種 DEPRECATED(bcg / growth)
- 5 ADR 涵蓋完整戰役決策

報表角色覆蓋:
- 戰情/早會:daily / weekly
- BU 主管:monthly / quarterly / half_yearly / forecast / strategy
- CEO/CFO:annual / ttm / market_intel
- 採購/PM:vendor / category / new_product / price_elasticity
- 行銷:promo / promo_compare / customer / market_intel
- 競品:competitor

Wave 4 待辦(受資料層 / 外部整合限制):
- clv (需 user_id 會員系統)
- competitor v4 五力(需外部 SKU/品牌力資料整合)
- inventory / operations / finance(需新 DB schema)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 12:50:25 +08:00
OoO
16b169d3ee feat(ppt): price_elasticity sweet spot report v3.1.0 (simplified)
All checks were successful
CD Pipeline / deploy (push) Successful in 2m56s
Wave 3.3:價格彈性簡化版(採購/PM 定價策略用)

generate_price_elasticity_ppt — 7 頁
- P1 封面:含集中度徽章(過度集中/主流明確/分布健康)+ 三句話結論
- P2 KPI:SKU 數/總訂單/甜蜜點價位/甜蜜點 SKU 數
- P3 各價位桶訂單分布橫條(找甜蜜點,焦糖橘=最高訂單桶)
- P4 各價位桶業績分布橫條(評估高價帶健康度,業界基準 30-50%)
- P5 甜蜜點 TOP 5 SKU(明星價位代表商品,新品設計參考)
- P6 AI 採購策略洞察
- P7 附錄

query_price_elasticity(category, days)
- 對 SKU 算平均售價(總業績 / 數量)
- 7 個價位桶分組(< 200 / 200-500 / 500-1K / 1K-2K / 2K-5K / 5K-10K / > 10K)
- 識別「訂單數最多」的桶 = 價格甜蜜點
- 計算高價帶(>NT$2K)業績佔比(業界基準健康 30-50%)
- 選 sweet_spot 桶內 TOP 5 SKU 作為代表

簡化版限制(為後續 ADR 註明):
- 非完整 price_elasticity(需要時間序列定價變化資料)
- 但能展示「該品類消費者最買單的價位帶」這個關鍵採購洞察

_ppt_ai_analysis 加 is_price_elast 分支
- 角色:採購主管 + PM
- 結構:甜蜜點解讀 / 高低價帶結構 / SMART 三層 / 風險預警
- 含「斷層補強」概念(識別 SKU 數明顯偏少的價位區間)
- max_tokens 1700

路由:
- /ppt price_elasticity                 全平台 90 天
- /ppt price_elasticity 美妝保養        單品類 90 天
- /ppt price_elasticity 美妝保養 30     自訂天數

Telegram 按鈕:「💰 價格彈性報告」

bump TEMPLATE_VERSIONS['price_elasticity'] = v3.1.0

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 12:48:15 +08:00
OoO
9862edeb44 docs(adr): ADR-025 PPT Wave 3 (new_product + market_intel_weekly)
Wave 3 完成 2 種橫向資訊整合型報表:
- new_product (95a74c3) — 30 天追蹤,PostgreSQL CTE 識別新品
- market_intel_weekly (fe3cba8) — 8 個外部 API 彙整,fail-safe 設計

累計報表清單:13 種有效 + 2 種 DEPRECATED + 4 種待資料層支援。

Wave 3 餘項(受資料層限制):
- clv (需 user_id)
- price_elasticity (需長期定價歷史)
- competitor v4 五力 (需外部 SKU/品牌力資料)

Wave 4 待辦(依資料層 schema):
- inventory / operations / finance

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 12:41:12 +08:00
OoO
fe3cba8496 feat(ppt): market_intel_weekly external signal aggregation v3.1.0
All checks were successful
CD Pipeline / deploy (push) Successful in 3m6s
Wave 3.2:市場情報週報 — 把 mcp_collector 所有外部 API 彙整成一份內部簡報。

generate_market_intel_weekly_ppt — 7 頁
- P1 封面:本週重點/市場機會/風險警訊三句話(從 AI 自動抽)
- P2 節慶日曆 + 季節情境(雙卡)
- P3 電商新聞 + Google 熱搜(雙卡)
- P4 Dcard 口碑 + YouTube 爆紅(雙卡)
- P5 天氣 + 匯率(雙卡,影響消費行為)
- P6 AI 整合洞察與行動建議
- P7 附錄

外部資料來源(mcp_collector_service / mcp_context_service):
- mcp_collector.get_holiday_context()  節慶日曆(靜態)
- mcp_collector.get_seasonal_context() 季節情境(靜態)
- get_ecommerce_news()  電商產業新聞(Gemini Grounding)
- get_taiwan_trends()   Google 台灣熱搜
- get_dcard_trends()    Dcard 熱門討論
- get_youtube_trending() YouTube 爆紅商品
- get_taiwan_weather()  台灣天氣
- get_twbank_exchange_rates() 台幣匯率

每個外部 API 用 _safe() wrapper,失敗時填預設文字「(本次擷取失敗或無資料)」。

_ppt_ai_analysis 加 is_market_intel 分支
- 角色:行銷情報分析師 + BU 主管
- 結構:本週市場大事 / 消費者情緒口碑 / 競爭態勢差異化 / SMART 三層 /
  外部風險預警
- max_tokens 2000

路由:
- /ppt market_intel    本週情報週報(自動對齊週一)

Telegram 按鈕:「🌐 市場情報週報」

bump TEMPLATE_VERSIONS['market_intel'] = v3.1.0

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 12:39:57 +08:00
OoO
95a74c3502 feat(ppt): new_product 30-day tracking report v3.1.0
All checks were successful
CD Pipeline / deploy (push) Successful in 2m35s
Wave 3.1:新品追蹤報告(PM/採購用)

generate_new_product_ppt — 9 頁
- P1 封面:含新品力徽章(強勁/穩健/偏弱/疲弱,依業績佔比)+ 三亮點
- P2 KPI:新品總數/業績/佔比/平均單品業績 + AI 解讀
- P3 新品整體日業績曲線(爬榜軌跡 matplotlib)
- P4 新品依品類分佈橫條
- P5-P7 新品 TOP 50(自動分頁)
- P8 AI PM 戰術洞察
- P9 附錄

query_new_products(days_recent=30, days_baseline=60)
- PostgreSQL CTE:recent EXCEPT early
  recent = 近 30 天有銷售
  early  = 31-90 天前有銷售
- 自動回傳:新品 TOP 50 / 子品類分佈 / 日業績曲線
- 含 ANY array 查詢新品集合的整體日業績

_ppt_ai_analysis 加 is_new_prod 分支
- 角色:PM 商品經理 + 採購主管
- 結構:新品力評估 / 明星新品識別 / 品類分佈與機會 / SMART 三層 / 風險預警
- SMART 行動含:加碼 TOP3 / 觀察排名 11-30 / 數據追蹤
- max_tokens 1800

業界基準:新品業績佔比 5-10% 為健康,>8% 強勁,<3% 偏弱

路由:
- /ppt new_product       預設近 30 天
- /ppt new_product 14    自訂追蹤天數

Telegram 按鈕:「🆕 新品 30 天追蹤」

bump TEMPLATE_VERSIONS['new_product'] = v3.1.0

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 12:37:06 +08:00
OoO
af6157f8ba docs(adr): ADR-024 PPT Wave 2 (forecast + promo_compare) + deprecate bcg/growth
All checks were successful
CD Pipeline / deploy (push) Successful in 2m41s
Wave 2 完成 2 種新報表:
- forecast_pre_event (9f04dc3) — 檔期前 14 天備戰策略 (BU 主管用)
- promo_compare (958f705) — 多活動 ROI 並排比較 (行銷主管覆盤)

正式廢除(DEPRECATED 標記,函式保留作 internal helper):
- bcg — 與 strategy 報表功能重疊(strategy 已含 BCG 五級分類)
- growth — 已被 quarterly + half_yearly + annual + ttm 完全取代

報表體系現況:16 種有效(v3 重做 6 + Wave 1 新增 8 + Wave 2 新增 2)+ 2 種
DEPRECATED;4 種角色覆蓋(採購/PM/行銷/CFO/CEO)。

forecast 核心:baseline 日均 × 21 天 × lift_factor,含 8 種檔期靜態知識
(雙11 1.65× / 母親節 1.40× 等),封面倒數天數徽章自動切換。

promo_compare 核心:N 場活動並排 KPI 表 + 拉抬 % 排序橫條 + 4 排名亮點
(最高拉抬/最低拉抬/最佳毛利/最高業績)。

Wave 3 待辦:market_intel_weekly / new_product / clv / price_elasticity
Wave 4 待辦:inventory / operations / finance(依資料層)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 12:30:35 +08:00
OoO
dda0a06bfd fix(strategist): cast metadata_json text to jsonb for stale alert dedupe
critic post-review #1 (HIGH): `_send_data_stale_alert` 的 dedupe SQL 對
`ai_insights.metadata_json` (Column(Text)) 直接套用 `->>` operator,PG 會
raise `operator does not exist: text ->> unknown`,被外層 try/except 吞掉,
導致 dedupe 完全失效,daily/weekly/monthly 同日 stale 會送 2-3 次告警噪音。

修法:`metadata_json::jsonb->>'report_type'` 即時 cast Text→JSONB 再取 key
(寫入端用 json.dumps,內容為合法 JSON)。

影響:
- 僅修 services/openclaw_strategist_service.py:353 一行
- grep 確認全 repo 僅此一處 `metadata_json->>` 用法
- 不動 dedupe 視窗 / telegram 發送 / _save_to_ai_insights
- 不動 tests / requirements.txt / 其他檔案

Regression:cast 每次 stale 告警跑一次,效能影響可忽略;若歷史 row
metadata_json 內容非合法 JSON,cast 會 raise 並被 try/except 吞掉,
行為退回現狀(dedupe 失效,但不影響告警送出)。

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 12:29:22 +08:00
OoO
958f705c8e feat(ppt): promo_compare multi-promo ROI report v3.1.0
Some checks failed
CD Pipeline / deploy (push) Has been cancelled
Wave 2.2:N 場促銷活動橫向比較(行銷主管覆盤用)。

generate_promo_compare_ppt — 5 頁
- P1 封面:含活動數徽章 + 排名亮點(最高拉抬/最低拉抬/最佳毛利)
- P2 並排 KPI 表:8 欄(活動/期間/天數/業績/訂單/毛利/業績拉抬/訂單拉抬)
  支援 14 場以下並排顯示
- P3 業績拉抬橫條圖(matplotlib,按拉抬 % 排序)
- P4 AI 跨活動洞察(成功要素 / 失敗診斷 / SMART 三層)
- P5 附錄

路由:
- /ppt promo_compare 母親節:2026/05/05-2026/05/14|520:2026/05/18-2026/05/22|618:2026/06/14-2026/06/22

每場活動透過 query_promo_comparison 取 ROI 數據,自動產生 4 個排名。

_ppt_ai_analysis 加 is_promo_cmp 分支
- 角色:資深行銷主管
- 結構:整體比較 / 勝出活動成功要素 / 失敗活動診斷 / SMART 三層
- max_tokens 1600

Telegram 按鈕:「🆚 多活動比較」(await:promo_compare)

bump TEMPLATE_VERSIONS['promo_compare'] = v3.1.0

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 12:28:17 +08:00
OoO
9f04dc3951 feat(ppt): forecast_pre_event report v3.1.0 (BU pre-event battle plan)
Some checks failed
CD Pipeline / deploy (push) Has been cancelled
Wave 2.1:檔期前瞻報告 — 給 BU 主管在檔期前 14 天決定備戰策略。

generate_forecast_pre_event_ppt — 7 頁
- P1 封面:含倒數天數徽章(備戰期/衝刺期/檔期中/已結束)+ 三段預期業績
- P2 KPI 三段對比:本期預期 / 去年同檔期 / Baseline 日均 / 已執行業績
- P3 去年同檔期業績曲線(matplotlib 折線,預測基準視覺化)
- P4 庫存盤點 TOP 30(基於 baseline 期銷量)
- P5 AI 戰術洞察
- P6 附錄

query_forecast_pre_event(event_name, event_date)
- baseline 期:檔期前 60-30 天(去除檔期前期效應)
- 去年同檔期:去年同日期 ± 7 天
- 本期準備窗口:檔期前 14 天到檔期後 7 天
- 預期業績 = baseline 日均 × 21 天 × lift_factor
- lift_factor 靜態知識(母親節 1.40 / 618 1.45 / 雙11 1.65 / 黑五 1.45 等)

_ppt_ai_analysis 加 is_forecast 分支
- 角色:BU 主管 + 行銷投放主管 + 採購三合一
- 結構:檔期定位 / 準備窗口進度 / 庫存戰術 / 廣告滿額門檻 /
  SMART 三層(檔期前7/當日+3/檔期後7)/ 風險預警
- max_tokens 2000

路由:
- /ppt forecast 母親節 2026/05/12
- /ppt forecast 618 2026/06/18

Telegram 按鈕:「🎯 檔期前瞻報告」(await:forecast_event)

bump TEMPLATE_VERSIONS['forecast_pre_event'] = v3.1.0

煙霧測試:7 頁 140KB 全綠。

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 12:25:42 +08:00
OoO
5461c92cf8 docs(adr): ADR-023 PPT system Wave 1 expansion (4 commits, 8 new types)
紀錄 Wave 1 擴展戰役:從 6 種 PPT 報表擴展到 14 種。

新增報表類型:
- vendor (b6fdb4f) — 採購主管視角,集中度警示 + 議價優先
- quarterly / half_yearly / annual / ttm (1af96f5) — period_review 共用
  generator 一份解 4 種,省 60% 程式碼
- category (d8260fc) — PM/採購視角,90 天縱向 + 子品類 + CTE 新進榜
- customer (48e3dac) — 行銷主管簡化 RFM,受限於無 user_id 做訂單級

技術亮點:
- 共用 Generator 模式(period_review 解 4 種)
- 期間徽章自動切換
- PostgreSQL CTE 做新進榜判定(recent EXCEPT early)
- 限制聲明的誠實設計(customer 無 user_id 註腳)

Wave 2-4 待辦清單見 ADR 內文。

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 02:20:05 +08:00
OoO
48e3dacfc9 feat(ppt): customer analytics report v3.1.0 (simplified RFM, no user_id)
All checks were successful
CD Pipeline / deploy (push) Successful in 2m49s
Wave 1.4:客戶/訂單分析報告(行銷主管用)— 受限於資料層無 user_id,
做訂單級分析而非完整 RFM。

generate_customer_analytics_ppt — 7 頁
- P1 封面:含客單定位徽章(高/中/低)+ 限制聲明(無 user_id 註腳)
- P2 KPI:總訂單/總業績/平均客單/高客單訂單數
- P3 客單價分佈:6 級分桶橫條(< NT$500 / 500-1K / 1-2K / 2-5K / 5-10K / >10K)
- P4 消費星期分佈:matplotlib 橫條(找熱門時段)
- P5 商品復購排行 TOP 30:同商品在多筆獨立訂單中的次數
- P6 AI 行銷洞察
- P7 附錄

query_customer_analytics
- AOV 分桶(CASE WHEN bucket)
- DOW 星期聚合(PostgreSQL EXTRACT(DOW))
- 復購商品(GROUP BY 商品名稱 HAVING COUNT(訂單) >= 5)

_ppt_ai_analysis 加 is_customer 分支
- 角色:資深行銷主管(10 年 RFM/CRM 經驗)
- 結構:訂單規模解讀 / 消費熱點 / 商品復購信號 / SMART 三層
- 長期建議:建立會員系統取得 user_id 升級完整 RFM

路由:
- /ppt customer            預設近 30 天
- /ppt customer 2026/04    指定月份

Telegram 按鈕:「👥 客戶/訂單分析」

bump TEMPLATE_VERSIONS['customer'] = v3.1.0

煙霧測試:7 頁 100KB 全綠。

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 02:17:48 +08:00
OoO
d8260fcd25 feat(ppt): category deep dive report v3.1.0 (90-day single category)
All checks were successful
CD Pipeline / deploy (push) Successful in 3m31s
Wave 1.3:單一品類 90 天縱向深度分析(PM/採購用)。

generate_category_deep_ppt(services/ppt_generator.py)— 12 頁
- P1 封面:含品類定位徽章(主力/成長/長尾)+ 新進榜商品 hero box
- P2 執行摘要:4 KPI(業績/訂單/毛利/SKU 數)+ AI 高階解讀
- P3 90 天日業績走勢(matplotlib 折線 + 日均線 + 高低點)+ 結論帶
- P4 子品類結構:橫條 + 帕雷托雙視圖
- P5-P7 TOP 50 商品(自動分頁)
- P8 TOP 30 廠商
- P9 新進榜商品專頁(近 30 天進榜,過去 60 天無交易判定)
- P10 AI 採購/PM 視角洞察
- P11 附錄

query_category_deep(routes/openclaw_bot_routes.py)
- 一次拉齊:kpis / daily(逐日) / top_products(50) / top_vendors(30) /
  sub_categories(L2) / new_products(近 30 天 vs 60 天前比對)
- 用 PostgreSQL CTE 做新進榜判定(recent EXCEPT early)

_ppt_ai_analysis 加 is_category 分支
- 角色:採購主管 + PM 商品經理
- 結構:品類整體 / 90 天趨勢 / 子品類結構 / SKU 與廠商組合 /
  SMART 三層 / 風險預警
- max_tokens 1800

路由:
- /ppt category 美妝保養        90 天深度(預設)
- /ppt category 美妝保養 30     自訂期間

Telegram 按鈕:「🗂 品類深度報告」(await:category_deep)
TODO:實作 await:category_deep 對應品類選擇互動(下一波)

bump TEMPLATE_VERSIONS['category'] = v3.1.0

煙霧測試:12 頁 300KB 全綠。

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 02:14:07 +08:00
OoO
1af96f5be4 feat(ppt): period_review unified generator for quarterly/half/annual/ttm
All checks were successful
CD Pipeline / deploy (push) Successful in 3m37s
Wave 1.2:用一份 generator 解 4 種時間維度報表(季/半年/年/TTM)。

generate_period_review_ppt(services/ppt_generator.py)— 12 頁
- 期間類型徽章自動切換(季報/半年報/年報/TTM 滾動)
- P1 封面:含業績狀態徽章 + elevator pitch + 期間動能
- P2 執行摘要:KPI v2 含 △% (vs 上季/上半/去年) + AI 解讀 + YoY 對比帶
- P3 月度業績走勢(matplotlib 折線:本期 + 上期 + 月均線 + 高低點)+ 4 卡指標
- P4 品類分析:橫條 + 帕雷托雙視圖
- P5-P7 TOP 50 商品(自動分頁)
- P8 TOP 30 廠商
- P9 MCP 市場情報
- P10 AI 結構化洞察
- P11 附錄

query_period_summary(routes/openclaw_bot_routes.py)
- 一次拉齊:kpis / monthly_breakdown / top_products(50) / top_categories(8) /
  top_vendors(30)
- 自動算月度聚合(PostgreSQL TO_CHAR)

路由層加 4 種 sub_type 分支:
- /ppt quarterly [YYYY/Q1-4]    當季或指定季
- /ppt half_yearly [YYYY/H1-2]  當半年或指定半年
- /ppt annual [YYYY]            當年或指定年
- /ppt ttm                      最近 12 個月(自動算到本月底)

每種自動抓三段資料:本期 + 上期同等 + 去年同期
- quarterly: 上季 + 去年同季
- half_yearly: 上半年 + 去年同半年
- annual: 去年 + 前年
- ttm: 上一個 TTM (24-12 月前) + 同上

_ppt_ai_analysis 加 is_period 分支
- 角色:策略顧問 + BU 主管 + CFO 三合一視角
- 結構:整體解讀 / 市場趨勢對位 / 月度走勢分析 / 品類結構 / 戰略級 SMART /
  風險預警
- SMART 行動分三層:下期立即啟動(30 天)/ 下期戰略(60-90 天)/
  下下期預備(6-12 月)
- max_tokens 2600,字數 1000-1300

Telegram 按鈕:報表選單加 4 顆季/半/年/TTM 按鈕

bump TEMPLATE_VERSIONS:quarterly / half_yearly / annual / ttm 全 v3.1.0

煙霧測試:4 種全綠,每份 12 頁 220KB。

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 02:10:14 +08:00
OoO
b6fdb4f473 feat(ppt): awaken vendor report + v3.1.0 procurement strategy upgrade
All checks were successful
CD Pipeline / deploy (push) Successful in 2m32s
Wave 1.1:把沉睡的 vendor generator 喚醒並全面升 v3.1.0:

generate_vendor_ppt(services/ppt_generator.py)— 8 頁
- P1 封面:含集中度警示徽章(健康分散 / 偏高 / 過高)+ 三句話策略要點
- P2 執行摘要:4 KPI 含 △% vs 上期 + 帕雷托 80/20 集中度結論帶
- P3 廠商業績排行:橫條 + 帕雷托雙視圖(matplotlib 暖色系)
- P4-P5 廠商明細表 TOP 30:含 △ 排名變化、🆕 新進榜、業績佔比 bar、
  毛利率紅綠燈(綠 ≥15% / 黃 8~15% / 紅 <8%)
- P6 AI 採購策略洞察(結構化 8 段)
- P7 附錄

query_vendor_summary(routes/openclaw_bot_routes.py)
- 期間(單月/自訂日期區間)廠商業績聚合
- 計算 sales / profit / margin / qty / orders
- 同步抓上期同等期間做 vs 上期 △ 比對

_ppt_ai_analysis 加 is_vendor 分支
- 角色:採購主管 + 供應鏈管理顧問
- 結構:整體解讀 / 集中度與供應風險 / 議價優先 / SMART 行動 / 風險預警
- SMART 行動分三層:立即執行 / 中期強化 / 長期結構(含 OEM/ODM 自有品牌)
- 引用 MARKET_TREND_2026 共用知識基底
- max_tokens 1800,字數 800-1000

路由綁定 _generate_ppt_cmd
- /ppt vendor          當月廠商報告
- /ppt vendor 2026/04  指定月份
- /ppt vendor 2026/04/01-2026/04/15  自訂期間
- 自動抓上期同等期間做 △ 比對

Telegram 按鈕(menu_keyboards.py 的 _submenu_reports)
- 新增「🏭 廠商業績報告」進報表選單

bump TEMPLATE_VERSIONS['vendor'] v2.0 (DEPRECATED) → v3.1.0

煙霧測試:本機 venv 跑 vendor PPT 生成 8 頁 200KB 全綠。

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 02:04:41 +08:00
OoO
abd722986e fix(autoheal): preflight + shell || true 結合性 — 解 24h 100% no-op
All checks were successful
CD Pipeline / deploy (push) Successful in 2m23s
Debugger 五階段方法論 root cause(2026-05-03):
ADR-020 政策層 100% 達成(reasoning 全 auto_fix=enabled),但 AiderHeal
執行層 24 小時 0 次 push 成功,全部 silent fail。

兩根因疊加:
  #1 (config) AIDER_REPO_PATH=/home/wooo/ewoooc 在 110 主機不存在
            → 寫 SOP docs/runbooks/aider-heal-110-setup-sop.md 給統帥手動執行
  #2 (code)  setup_cmds 結尾 `git stash 2>&1 || true` 因 shell 結合性等同
            `(A && B && C && D) || true`,cd 失敗整 chain rc=0 被吞,
            line 261 if rc != 0 永不觸發 → setup_failed 從未被 log
  #4 (code)  缺 preflight,環境壞掉時靜默走完整 pipeline 印 no_diff

本次程式碼修復:
  • execute_code_fix 開頭加 L0 preflight(test -d $REPO/.git)
    失敗 fail-fast + Telegram 嚴重告警 + 指向 SOP
  • setup_cmds 改 `A && B && C && (D || true)` 用 subshell 限縮 || true
  • 全檔 5 處 `cd $REPO_PATH` 統一改 `cd shlex.quote(REPO_PATH)`
    避免下次有人複製 cd chain 又踩同類 shell quoting bug

SOP 同步處理 critic High-2 + Medium-6:
  • 步驟 2 改用 SSH clone(git clone gitea-autoheal:...)
    避免 HTTP clone 在 private repo 卡帳密 + 跟步驟 1 部署的 key 不關聯
  • 步驟 4b 修引號嵌套(heredoc + 單引號保護),原版永遠 false positive

Critic 審過 Approve to commit;Medium-2/3/4(速率限制 / log 加 stderr /
新增 preflight unit test)排 follow-up,不阻擋本次。

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 01:55:34 +08:00
OoO
5daa1a45d8 fix(strategist): plug stale gate gaps in daily/monthly + psutil dep + complete stale shape (critic post-review)
critic post-review 對 commit 9158bbe 找到 3 個 BLOCKER,本 patch 補完。

#1 daily/monthly 路徑沒套 stale gate(Critical)
- generate_daily_report() 在 _fetch_sales_summary(7) 後立刻檢查 sales.get("stale"),
  避免 daily_sales_snapshot 過期時每天 09:00 復發 NT$0 偽日報
- generate_monthly_report() 在 _fetch_monthly_sales_summary 後檢查
  revenue==0 and sku_count==0(_fetch_monthly_sales_summary 沒內建 stale 機制,
  以「無資料」當訊號),避免月初產出 NT$0 偽月報
- 抽出 _send_data_stale_alert(report_type, last_date, period) 統一三條路徑共用,
  以 ai_insights 表查近 24h 同 report_type 的 data_stale_alert 紀錄做 dedupe,
  避免每天 daily/weekly 三份報告同時觸發 → 一天送多次告警噪音
- weekly stale 分支改用 _send_data_stale_alert(return shape 維持 status="error"
  不動,保 9158bbe weekly dedupe/cache 機制下游語意)
- daily/monthly 採 critic 建議的 status="skipped";scheduler 既有 task 不檢查
  status 也不 raise,EventRouter 不會被誤觸

#2 psutil 沒在 requirements.txt(Critical)
- requirements.txt 加 psutil>=5.9(ADR-019 Phase 2 要求 production 必裝)
- elephant_alpha_autonomous_engine._get_system_load_percentage 加註解:
  ImportError fallback 是 queue-based 估算(pending=14→70%、≥18→90%),
  與真實 CPU 無關,僅 dev defensive;prod 觸發即代表容器映像漏裝

#9 _fetch_sales_summary stale 分支 return shape 不完整(High)
- stale 分支補完 daily/current_7d_revenue/prev_7d_revenue/wow_pct/sku_count
- 數值欄位用 None(非 0):未套 stale gate 的上游 caller 在 prompt template
  `:,.0f` 會 raise TypeError,比靜默 0 明顯,迫使呼叫端必須 stale gate

三問自審:
- 方案正確:daily 不再發 NT$0(_fetch_sales_summary 後立刻 gate);psutil 會被
  pip install;stale shape None 在所有 caller 路徑要嘛被 gate 擋下要嘛 raise
- 影響完整:grep 確認 _fetch_sales_summary 三 caller(weekly/daily/monthly via
  _fetch_monthly_sales_summary)皆已加 gate;無下游依賴 data_stale return 字串
- Regression 風險:stale shape 改 None 為純擴充無 caller 取數值欄位;scheduler
  只讀 period/chart_count/action_count 不檢查 status;monthly revenue=0 gate
  在實務 P0 異常時告警,比靜默產 NT$0 月報可接受

不在本 patch scope(critic 任務描述明示禁動):
- 9158bbe weekly dedupe/cache 機制(_acquire_weekly_strategy_send_lock 等)
- elephant_alpha Phase 1 已修部分(trigger/dispatch/method raise)
- run_scheduler.py 排程設定
- tests/ 內任何測試

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 01:54:21 +08:00
OoO
993bdda1fd feat(ppt-ai): inject shared 2026 Taiwan e-commerce market knowledge to all 6 prompts
All checks were successful
CD Pipeline / deploy (push) Successful in 2m25s
完成 project memory 待補事項:抽取共用市場趨勢常數 + 補齊未升級的 prompt。

新增 MARKET_TREND_2026 共用常數(routes/openclaw_bot_routes.py):
- 6 大關鍵檔期 + 拉動幅度(母親節 +30~50% 美妝 / 618 全品類 +30~50% / 雙11 +50~80%)
- 6 條 2026 熱門賽道(永續美妝/母嬰高端/機能性食品/IP 聯名/男性保養/寵物經濟)
- 4 大平台競爭定位(蝦皮/PChome/酷澎/momo)

Inject 到 5 條 prompt(monthly/strategy/promo/competitor/else):
- 月報、策略、促銷:原 prompt + MARKET_TREND_2026 知識基底
- 競品比較:補上 2026 熱門賽道做美妝/保健/母嬰專項分析的事實基礎
- daily/weekly(else 分支):完整重寫從 250 字 → 350-450 字 SMART 框架
  + 含市場機會與風險段(檔期卡位 + 競品風險)

bump 版本(所有 6 種 v3.x):
- daily   v3.0.2 → v3.1.0
- weekly  v3.0.2 → v3.1.0
- monthly v3.1.3 → v3.1.4
- strategy v3.0   → v3.1.0
- competitor v3.0 → v3.1.0
- promo   v3.0   → v3.1.0

效果:6 種報表 AI 分析現在都有共同的市場事實基底,跨報表敘事一致;
單一資料來源避免「不同報表給的市場數字打架」問題。

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 01:42:43 +08:00
OoO
9010a4e6fa docs(adr): add ADR-022 PPT v3 redesign + warm paper + matplotlib + cache versioning
紀錄本次 PPT 全面重做的架構決策:
- 視覺:暖紙風(_BG_PAPER #F3EEE2)取代暖墨黑封面
- 圖表:matplotlib 暖色系(橫條/折線/帕雷托)取代 python-pptx 原生
- 字型:lxml 直寫 a:latin/a:ea 中英分軌(Consolas + JhengHei)
- 快取:TEMPLATE_VERSIONS 字典自動注入 cache key (tpl_ver)
- AI prompt:升級到顧問深度(市場趨勢脈絡 + SMART 框架)
- 安全:admin 白名單(OPENCLAW_ADMIN_USER_IDS)+ cleanup dry_run 預設

涵蓋 8 commit chain:38967ce → 3b0b4b352c06f61c81866b5a2b09c7b7cee92b80355a7012f

Critic 全清紀錄:0 critical / 2 HIGH / 4 medium / 3 info 全部修補。

對應 memory:
- reference_ppt_system.md(既存)已更新到 v3 實況
- project_ppt_v3_campaign_20260502.md(新建)戰役紀錄含三大踩坑
- feedback_template_version_cache_pattern.md(新建)可重用設計模式

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 00:25:09 +08:00
OoO
5a7012f1fa fix(ppt): AI parser drops empty-body sections + cap raised 6→10
All checks were successful
CD Pipeline / deploy (push) Successful in 2m33s
實戰問題:升級 monthly AI prompt 後,AI 輸出多了【行銷與銷售行動建議
— SMART 框架】這個「主段」加 3 個 ■ 子段(本週/本月/下月)。原 parser:

1. ■ 子段被當成新 section(這是正確行為)
2. 但「行銷與銷售行動建議」主段自己 body 變空殼
3. 顯示成「(本段無內容)」醜陋占位
4. 加上 sections[:6] 切斷,後面的競爭定位/風險預警被丟掉

修補(services/ppt_generator.py:_parse_ai_sections):
- 過濾空 body section(len(body) < 5 視為空殼)
- 上限放寬 6 → 10(容納升級 prompt 後的 9 段:整體/市場/品類/熱銷/
  MCP/本週/本月/下月/風險)

驗證:模擬 9 段輸入 → 過濾後得 6 個非空段,正確包含本週/本月/下月。

bump monthly v3.1.2 → v3.1.3

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 00:15:19 +08:00
OoO
92b80352cb feat(ppt-ai): upgrade prompts to professional sales/marketing depth + 2026 market trends
All checks were successful
CD Pipeline / deploy (push) Successful in 2m33s
需求:簡報 AI 分析必須詳盡且專業,能直接幫助銷售/行銷策略制定,
反映 2026 年台灣電商當下市場方向與趨勢。

升級三份 prompt(monthly / strategy / promo):

【共通強化】
- 角色從單純「分析師」升級為三合一:
  策略顧問(BCG/麥肯錫經驗)+ 行銷主管(廣告 ROI、檔期)+ 採購(選品邏輯)
- 明確指明客戶與用途:「BU 主管會用本報告做下週的庫存與行銷預算決策」
- 全部加「市場趨勢脈絡」段,必須觸及:
  (a) 當期關鍵檔期(母親節/520/618/雙11/雙12)對品類的歷史拉抬幅度
  (b) 2026 熱門賽道:永續美妝、母嬰高端化、IP 聯名、敏弱肌、銀髮保健、
     男性保養、寵物經濟、機能性食品
  (c) 平台競爭:vs 蝦皮/PChome/酷澎 的免運門檻、直播帶貨、會員訂閱
- 行動建議升級為 SMART 框架(Specific / Measurable / Achievable /
  Relevant / Time-bound),每條必須含商品名 + 量化目標 + 期限
- 禁用「可能/也許/建議考慮」等模糊用詞,要明確「必須做X、目標Y、期限Z」

【月報 monthly】
- 段落結構從 5 段擴為 7 段:整體解讀 / 市場趨勢 / 品類結構 / 熱銷洞察 /
  MCP 整合 / SMART 行動建議 / 競爭定位與風險
- 行動建議從 6 條(每段2條)擴為 9 條(每段3條),含本週/本月/下月分層
- 字數 500-700 → 900-1200,max_tokens 1600 → 2400

【策略 strategy】
- 加市場趨勢脈絡段、SMART 框架行動建議
- 字數 400 → 600-800,max_tokens 900 → 1400

【促銷 promo】
- 市場信號解讀段升級為三段式(檔期對位 / 品類熱度 / 價格敏感度)
- 結合 2026 台灣電商熱搜賽道

效果:報告從「描述業績」升級為「告訴 BU 主管下週要做什麼、目標多少、何時完成」。

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 00:08:36 +08:00
OoO
00591c5489 feat(ea-hitl): ADR-021 EA 升級審核 pre-fetch + 競價告警金額影響量化
根治 2026-05-02 統帥反映的三層 EA escalation 訊息空泛問題:

1. _escalate_to_human 對 price_drop_alert / market_opportunity /
   threat_escalation 三類觸發,送 Telegram 前先 await Hermes 取具體
   SKU 清單覆蓋 plan 元流程文字(5s 短超時,失敗 fallback 原 plan)
2. NemoTron 競價告警新增 _compute_business_impact helper:
   過去 7 日營收流失(gap_pct>0 才算)+ 跟進競品建議價,
   dispatch 主路徑 / 防線二 / Hermes rule fallback 三條全部 Python
   獨裁注入,告警含「📉 NT$ X」「🎯 NT$ Y」具體金額
3. 補實 telegram_bot_service.handle_callback 的 momo:eig: prefix
   handler,HITL「🛑 忽略此事件」按鈕首次有對應 audit 寫入

Critic 審查通過(5 項必修全綠):
- Critical-1: user_label HTML escape 防 Telegram username XSS
- High-1: pre-fetch 改 asyncio.wait_for(5s) 防阻塞 escalation
- High-2: 全部行缺金額時 return None 觸發 plan fallback
- Medium-2: 空 event_id callback 拒絕避免 audit 污染
- Medium-3: gap_pct≤0 時 revenue_loss_7d 強制歸 0 不誤導降價

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 00:03:38 +08:00
OoO
650ef4c5db feat(deploy): ADR-020 — momo-app 容器加 CODE_REVIEW_AUTO_FIX_ENABLED 預設 true
All checks were successful
CD Pipeline / deploy (push) Successful in 12m10s
接續 6cad59f:Python 端預設已改 true,但 188 容器透過 docker-compose
讀 env_file: .env,.env 沒設此 key 時容器仍視為 false(reasoning
顯示 auto_fix=flag_disabled)。本次在 momo-app environment 區塊明確
注入主開關,採 `${CODE_REVIEW_AUTO_FIX_ENABLED:-true}` 機制:
  • .env 沒設 → true(預設生效)
  • .env 顯式 true → true
  • .env 顯式 false → false(保留 escape hatch)

CD pipeline 偵測到 docker-compose.yml 變更會走 rebuild path
(force-recreate momo-app),無需手動干預。

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-02 23:52:49 +08:00
OoO
c7b7ceeb8d fix(ppt): line chart resilience — sparse data + dense xtick + inset legend
Some checks failed
CD Pipeline / deploy (push) Has been cancelled
實戰在 188 prod 抓到的問題:N=1 時 title/legend/data marker 全擠在頂部。

修補:
- 加 `sparse = n_pts <= 2` 旗標,N<=2 時:
  * 略過平均水平線(單點下無意義且標籤撞 title)
  * marker 加大(5 → 7)讓單點更顯眼
  * 中央加「⚠ 期間僅 N 個資料點」提示框(圓角米底+焦糖橘邊)
  * legend 改 lower right inset(避開 title)
  * x 軸 set_xlim 加邊距避免 marker 貼牆
- 正常 N>=3:
  * legend 從 bbox_to_anchor 上方移到 axes 內 upper right
    (frameon=True 米底邊框,避免與 title 撞)
  * xticklabel 在 N>14 時 rotation=45 ha=right(避免 30 點擠成一團)
  * title pad 加大為 18

bump 版本:
- daily   v3.0.1 → v3.0.2
- weekly  v3.0.1 → v3.0.2
- monthly v3.1.1 → v3.1.2

本機驗證:
- N=1:「資料不足」提示框正確顯示,無重疊
- N=30:30 個 xticklabel 旋轉 45° 清楚分離,legend 右上 inset 不撞 title

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-02 23:52:04 +08:00
OoO
6cad59f83e feat(code-review): ADR-020 全自動修復政策 — 拆掉 CRITICAL/HIGH HITL 閘門
All checks were successful
CD Pipeline / deploy (push) Successful in 2m23s
post-deploy code review pipeline 改為「任何 finding 一律觸發 AiderHeal」,
局部覆寫 ADR-012 L3 HITL(不影響 schema migration / 流量切換 /
customer-facing 廣播 / AIOps prod SSH 等其他 L3 場景)。安全網改為
Git revert + Gitea CI/CD 健康檢查 + 主開關 CODE_REVIEW_AUTO_FIX_ENABLED。

實作:
  • _ea_orchestrate / _guard_ea_decision / rule fallback 三條路徑統一為
    has_findings AND AUTO_FIX_ENABLED → auto_fix=true
  • _guard 強制 LLM 即使回 auto_fix=False 也升級為 true(核心保證)
  • CODE_REVIEW_AUTO_FIX_ENABLED 預設 false → true
  • Telegram 文案移除「需人工審查」,改顯示主開關狀態
  • action_plan status pending_review → auto_disabled(語意對齊)
  • aider_heal_executor 標頭 ADR-014 → ADR-020、補「直推 main」分支策略

文件:
  • 新增 docs/adr/ADR-020-code-review-full-autoheal.md
  • ADR-012 加 Note 行反向引用 ADR-020
  • README 索引收錄

測試:tests/test_code_review_pipeline_security.py 反轉 HITL 期望,
新增 5 case(含 LLM 降級被 guard 拒絕、LLM human_review_needed=true 被改 false)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-02 23:44:01 +08:00
OoO
b5a2b09445 fix(ppt): matplotlib CJK fallback covers container Noto CJK JP variant
All checks were successful
CD Pipeline / deploy (push) Successful in 2m19s
實戰驗證在 188 容器內發現:matplotlib font_manager 從 fonts-noto-cjk
ttc 檔只載入 'Noto Sans CJK JP' / 'Noto Serif CJK JP' 兩個變體(TC/SC/HK/KR
名稱未列入 ttflist),導致原本 fallback 清單比對失敗 → font.family 退到
'sans-serif'(DejaVu Sans)→ 中文 glyph 全部缺失印出 UserWarning。

修正:
- _mpl_setup() fallback 清單加入 'Noto Sans CJK JP' / 'Noto Serif CJK JP'
- 最終 fallback 加 substring match(涵蓋未列入但名稱含 CJK/PingFang/
  JhengHei/YaHei/Source Han/WenQuanYi/Hiragino 的字型)
- _mpl_horiz_bar_png 內重複的 cjk_candidates 邏輯移除,改呼叫 _mpl_setup
  避免兩處清單漂移

註:Noto Sans CJK JP ttc 檔本身含完整 CJK Unified Ideographs,可正常
渲染中文(漢字共用),只是字型名稱叫 JP 而已。

bump 模板版本(舊圖表中文方塊版本快取應失效重生):
- daily   v3.0   → v3.0.1
- weekly  v3.0   → v3.0.1
- monthly v3.1   → v3.1.1

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-02 23:38:51 +08:00
OoO
1c81866541 fix(ppt): final critic cleanup — Medium-1 OOXML order + Info-1/2 docs
All checks were successful
CD Pipeline / deploy (push) Successful in 2m29s
清掉剩餘 critic finding(Medium-1 + Info-1 + Info-2):

Medium-1: _set_run_fonts 違反 OOXML CT_TextCharacterProperties 子元素順序
- 抽出 _insert_rpr_child(rPr, tag) helper:依 ECMA-376 §21.1.2.3 規定
  的順序表(_RPR_CHILD_ORDER)找正確位置插入
- 找第一個排在 target 之後的子元素 → insert 前面;否則 append
- 當前 from-scratch 場景安全;未來改讀模板 .pptx 時也不會踩雷
- 驗證:產生 monthly v3.1,399 個 rPr 全部符合 schema 順序,0 違反

Info-1: cleanup_expired_ppt_cache docstring 補語意說明
- 明確說明 dry_run=True/False 時 deleted_files / deleted_rows / freed_bytes
  欄位語意分別為「將刪除」預估值 vs「已實刪」實際值

Info-2: TEMPLATE_VERSIONS 標記退役 type
- growth / vendor / bcg 三個 type 從未實際落地(依 ADR-014 校正 2026-04-28)
- 加 DEPRECATED 註解,避免後人誤以為已支援

Info-3 SKIP(評估後不做):
- get_template_version import 改放模組頂部會 trigger ppt_generator 模組級
  REPORTS_DIR.mkdir() 副作用,read-only filesystem 環境會掛
- 保留延遲 import 是 graceful degradation 的 intentional 設計

至此 critic 38967ce 審查清單全綠:
- 0 critical, 2 HIGH (3b0b4b3), 4 medium (52c06f6 + 本 commit), 3 info

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-02 17:39:27 +08:00
OoO
52c06f6861 fix(ppt): admin guard for destructive /cache commands (critic Medium-3)
All checks were successful
CD Pipeline / deploy (push) Successful in 2m14s
Critic Medium-3:群組內任意成員可執行破壞性快取指令的問題。

新增機制:
- ADMIN_USER_IDS:新增 OPENCLAW_ADMIN_USER_IDS 環境變數
  逗號分隔的 user_id;未設時退回 ALLOWED_USERS(向後兼容)
- _is_admin(user_id):fail-closed 判定函式
- _CURRENT_USER_ID_CTX:ContextVar 在 webhook 入口(msg + callback)
  set 當前 user_id,避免改 handle_cmd 30+ 處呼叫端簽名

權限模型:
| 指令                              | 權限    | 行為                |
| /cache status                     | 已授權  | 任何已授權用戶可看  |
| /cache cleanup [days]             | 已授權  | 預設乾跑可預覽      |
| /cache flush <type>               | admin   | 拒絕非 admin        |
| /cache cleanup [days] confirm     | admin   | 拒絕非 admin        |
| /cache cleanup [days<1] confirm   | -       | 強制乾跑(防呆)    |

非 admin 嘗試破壞性指令時,回傳清楚錯誤訊息引導設定環境變數。
admin 操作會額外寫 sys_log.warning 留軌跡(含 user_id)。

煙霧測試:
- syntax OK
- _is_admin(None) / _is_admin("abc") / _is_admin(unknown_id) 皆 False
- ContextVar set/get 行為正確

剩餘 Medium 1/2 + Info 類後續再處理(非緊急)。

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-02 17:35:48 +08:00
OoO
3b0b4b3d42 fix(ppt): address critic findings on commit 38967ce (HIGH-1, HIGH-2, Medium-4)
All checks were successful
CD Pipeline / deploy (push) Successful in 2m27s
Critic 審查 38967ce 找出 2 HIGH + 4 medium,本 commit 修最緊急三項:

HIGH-2: cleanup_expired_ppt_cache 預設 dry_run=False 危險
- 函式 default 改 dry_run=True(呼叫方需明確傳 False 才實刪)
- launchd 排程腳本改用 DRY_RUN 環境變數,預設 false→實刪,
  但測試時可 DRY_RUN=true 安全跑
- /cache cleanup Telegram 指令預設乾跑,需加 confirm 才實刪
- /cache cleanup days<1 強制乾跑(防呆)

HIGH-1: matplotlib 三個 helper 缺 try/finally → 渲染失敗洩漏 figure
- _mpl_horiz_bar_png / _mpl_line_chart_png / _mpl_pareto_chart_png
  全部用 try/except/finally 包住,例外時 plt.close() 仍執行
- 同時讓渲染失敗回 None(呼叫端自然 fallback 到原生 chart)

Medium-4: scripts/ppt_cleanup.sh PROJECT_DIR 寫死
- 改用相對路徑解析(cd $SCRIPT_DIR/..),手動執行不再需要設環境變數
- VENV_PY 找不到時 fallback 到系統 python3(容器友善)
- 新增 DRY_RUN 環境變數開關(預設 false)

煙霧測試:
- syntax OK (services/ppt_generator.py + routes/openclaw_bot_routes.py)
- monthly v3.1 重生 10 頁 290KB
- cleanup_expired_ppt_cache dry_run default = True ✓

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-02 17:23:02 +08:00
OoO
38967ceea3 feat(ppt): redesign all 6 reports to professional standard + cache versioning
All checks were successful
CD Pipeline / deploy (push) Successful in 13m18s
PPT 模板全面升版至市場專業標準(McKinsey / BCG 月報級別):

Monthly v3.1(10 頁)
- 暖紙感封面(去黑底)+ elevator pitch(亮點/警訊/動能徽章)
- KPI 卡含 △% vs 上月 + 紅綠燈、YoY 同期對比帶
- matplotlib 業績趨勢折線(本月+上月+日均線+高低點)
- 品類分析雙視圖:橫條 + 帕雷托累計(80% 主力線)
- TOP 50 商品(自動分頁)+ vs 上月 △ 排名變化 / 🆕 新進榜
- MCP 情報 4 卡片結構化、AI 行動結構化分區、附錄頁

Daily / Weekly / Strategy / Promo / Competitor v3.0
- 統一暖紙封面、AI 頁去黑底改暖紙 + 焦糖橘色條
- 日週改 matplotlib 折線(含日均線、高低點)
- 全部加附錄頁(資料來源 / 計算口徑 / 模板版本)

Cache 版本控制
- TEMPLATE_VERSIONS 字典自動注入 cache key (tpl_ver)
- 模板升版舊快取自動 miss → 重生
- 新增 _invalidate_ppt_cache() 與 cleanup_expired_ppt_cache() helper
- 新增 /cache status / flush / cleanup Telegram 指令

字型系統
- _set_run_fonts() 用 lxml 直寫 a:latin/a:ea,中英分軌
- 中文走 Microsoft JhengHei,數字/英文走 Consolas(點陣等寬)
- Dockerfile 加 fonts-noto-cjk + fonts-noto-cjk-extra

部署排程
- scripts/install_ppt_cleanup.sh 一鍵安裝 launchd(每日 03:15)
- scripts/ppt_cleanup.sh 清 7 天前過期 PPT 檔 + DB row

資料層
- routes monthly: query_monthly_summary LIMIT 10 → 50,補 orders 欄位
- routes monthly: 拉 prev_month / prev_year 比較資料供 KPI △ 與商品 △ 計算

煙霧測試 6/6 全綠:
- 日報 v3.0 (5 頁) / 週報 v3.0 (6 頁) / 月報 v3.1 (10 頁)
- 策略 v3.0 (6 頁) / 促銷 v3.0 (6 頁) / 競品 v3.0 (5 頁)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-02 16:26:27 +08:00
OoO
0232dbb902 test(openclaw): assert /menu returns full main menu keyboard 2026-05-02 16:13:43 +08:00
OoO
3f40089d8c fix(openclaw): show full main menu for wakeup phrases
All checks were successful
CD Pipeline / deploy (push) Successful in 2m44s
2026-05-02 16:12:30 +08:00
654 changed files with 231187 additions and 29019 deletions

View File

@@ -5,8 +5,9 @@ set -u
HOOK="$(cd "$(dirname "$0")/.." && pwd)/commit-quality.js"
PASS=0; FAIL=0
# 真實格式 Telegram Token測試字串非活躍憑證
TOKEN='8610496165:AAFOlcWV4oRUSC2TI-fYux7JV97fjNzsYR8'
# 真實格式 Telegram Token測試字串非活躍憑證;分段避免完整 token 形態入庫。
TOKEN_PREFIX='8610496165:AAFOlcWV4o'
TOKEN="${TOKEN_PREFIX}RUSC2TI-fYux7JV97fjNzsYR8"
run_case() {
local name="$1"; local input="$2"; local expect="$3" # expect: allow|deny

View File

@@ -47,6 +47,40 @@ EMAIL_RECEIVER=receiver_email@gmail.com
PUBLIC_URL=http://your_server_ip:port
NGROK_AUTH_TOKEN=your_ngrok_auth_token
# ==========================================
# Webcrumbs 共用 UI Runtime
# ==========================================
# [預設 true] 啟用 momo-pro 全站 shell 載入自架 Webcrumbs runtime
WEBCRUMBS_ENABLED=true
# [預設] 共用 Webcrumbs/Open Design 工具入口;正式頁面載入不直接依賴此跨域 TLS
WEBCRUMBS_BASE_URL=https://webcrumbs.wooo.work
# [預設 shared-ui-poc-0.1.0] 生產環境必須固定版本,不使用官方 @latest
WEBCRUMBS_RUNTIME_VERSION=shared-ui-poc-0.1.0
# [預設] momo-pro 同源 asset proxy避免跨域憑證/Basic Auth 影響正式頁面
WEBCRUMBS_RUNTIME_PATH=/webcrumbs-assets/loader/webcrumbs-compatible-loader.js
# [選填] 若實際 runtime URL 與 RUNTIME_PATH 不同,用此欄位直接覆寫
WEBCRUMBS_RUNTIME_URL=
# [預設] 共用 plugin base各 plugin 應使用版本化子目錄
WEBCRUMBS_PLUGIN_BASE_URL=/webcrumbs-assets/plugins
# [預設] 188 user-space Shared UI Hub只允許 proxy loader/plugins/demo
WEBCRUMBS_ASSET_UPSTREAM_URL=http://192.168.0.188:18088
# ==========================================
# Image / Release Tagdocker-compose*.yml
# ==========================================
MOMO_IMAGE=registry.wooo.work/wooo/momo-pro-system
VERSION=stable
FRONTEND_IMAGE=registry.wooo.work/wooo/momo-frontend
FRONTEND_VERSION=stable
# ==========================================
# 市場情報模組設定(預設全部關閉)
# ==========================================
# Phase 1 僅允許安全骨架;正式爬蟲與 DB 寫入需逐步開啟
MARKET_INTEL_ENABLED=false
MARKET_INTEL_CRAWLER_ENABLED=false
MARKET_INTEL_WRITE_ENABLED=false
# ==========================================
# 通訊模組設定(從環境變數讀取)
# ==========================================
@@ -58,6 +92,7 @@ ALERT_WEBHOOK_PASSWORD=your_secure_webhook_password_here
AUTO_FIX_ENABLED=true
# --- GitLab CI/CD ---
GITLAB_ENABLED=false
GITLAB_URL=http://192.168.0.110:8929
GITLAB_TOKEN=your_gitlab_token_here
GITLAB_PROJECT_ID=1
@@ -81,6 +116,8 @@ GUNICORN_WORKER_CLASS=gthread
GUNICORN_THREADS=4
# [預設 300] 長查詢 / 報表匯出 timeout 秒數
GUNICORN_TIMEOUT=300
# [預設 false] worker 啟動時預熱 Dashboard 快取;正式環境通常維持 false
DASHBOARD_PREWARM_ON_WORKER_INIT=false
# ==========================================
# Database Settings
@@ -92,12 +129,24 @@ POSTGRES_USER=momo
POSTGRES_PASSWORD=your_secure_postgres_password_here
POSTGRES_DB=momo_analytics
# Generic database URL / discrete keys used by tools and deployment scripts
DATABASE_URL=postgresql://momo:your_secure_postgres_password_here@momo-postgres:5432/momo_analytics
DATABASE_HOST=momo-postgres
DATABASE_PORT=5432
DATABASE_USER=momo
DATABASE_PASSWORD=your_secure_postgres_password_here
DATABASE_DB=momo_analytics
# SQLite Configuration (Development/Backup)
SQLITE_PATH=data/momo_database.db
# Database Type Selection (postgresql or sqlite)
USE_POSTGRESQL=true
# Redis cache / queue optional endpoint
REDIS_HOST=redis
REDIS_PORT=6379
# ==========================================
# Google Drive 自動匯入設定
# ==========================================
@@ -111,16 +160,51 @@ GDRIVE_FILE_PATTERN=即時業績_當日
# ==========================================
# Hermes 3 競價情報分析Module 2 / ADR-012
# ==========================================
# [預設 http://192.168.0.111:11434] Hermes Ollama 端點(內網免認證
HERMES_URL=http://192.168.0.111:11434
# [選填] Hermes Ollama 端點;留空時自動走 GCP-A → GCP-B111 預設不承接 Hermes 批量分析
# 僅允許 http://34.87.90.216:11434、http://34.21.145.224:11434、http://192.168.0.111:11434
HERMES_URL=
# [預設 120] Hermes 推理 timeout批量 300 筆預估 ~90s
HERMES_TIMEOUT=120
# [預設 5m] Hermes runner 熱駐留;禁止回到 24h避免 GCP-B/111 長駐高負載
HERMES_KEEP_ALIVE=5m
# [預設 false] 僅救急時才允許 Hermes LLM 落到 111平時失敗交給規則/DB fallback
HERMES_ALLOW_111_FALLBACK=false
# [預設 HERMES_URL] Embedding 服務主機ADR-003 對齊embedding 走 Hermes 主機)
EMBEDDING_HOST=http://192.168.0.111:11434
# [預設 45] Embedding API timeout優先使用 Ollama /api/embed舊節點 fallback /api/embeddings
EMBEDDING_TIMEOUT=45
# [選填] Embedding 服務主機;留空時自動走同一條 Ollama 三主機級聯
EMBEDDING_HOST=
# [預設 30] Embedding API timeout優先使用 Ollama /api/embed舊節點 fallback /api/embeddings
EMBEDDING_TIMEOUT=30
OLLAMA_EMBED_MAX_TIMEOUT=30
OLLAMA_EMBED_KEEP_ALIVE=1m
PARTIAL_BACKUP_MIN_AGE_MINUTES=60
OLLAMA_EMBED_MAX_CHARS=4000
OLLAMA_EMBED_GCP_FAILURE_COOLDOWN_SEC=60
OLLAMA_EMBED_GCP_FAILURE_NOTICE_SEC=30
# [預設 true] 背景 embedding 會讀 host_health_probes跳過最近 runtime unhealthy 的 GCP 節點
OLLAMA_EMBED_HOST_HEALTH_SKIP_ENABLED=true
OLLAMA_EMBED_HOST_HEALTH_SKIP_WINDOW_MINUTES=20
# 111 Mac final fallback guardrail and allowlist proxy
OLLAMA_111_CIRCUIT_BREAKER_ENABLED=true
OLLAMA_111_CIRCUIT_CACHE_SEC=60
OLLAMA_111_CIRCUIT_WINDOW_MINUTES=60
OLLAMA_111_CIRCUIT_PCT=5
OLLAMA_111_CIRCUIT_MIN_TOTAL=20
OLLAMA_111_CIRCUIT_MIN_111=5
OLLAMA_111_USAGE_ALERT_ENABLED=true
OLLAMA_111_USAGE_ALERT_WINDOW_MINUTES=60
OLLAMA_111_USAGE_ALERT_PCT=5
OLLAMA_111_USAGE_ALERT_MIN_TOTAL=20
OLLAMA_111_USAGE_ALERT_MIN_111=3
OLLAMA_111_USAGE_ALERT_DEDUP_SEC=3600
OLLAMA111_PROXY_ALLOWED_CIDRS=127.0.0.1/32,192.168.0.111/32,192.168.0.188/32
OLLAMA111_PROXY_LISTEN_HOST=192.168.0.111
OLLAMA111_PROXY_LISTEN_PORT=11434
OLLAMA111_PROXY_TARGET_HOST=127.0.0.1
OLLAMA111_PROXY_TARGET_PORT=11434
OLLAMA111_PROXY_LOG_LEVEL=INFO
OLLAMA111_PROXY_REJECT_LOG_DEDUP_SEC=60
# ==========================================
# Elephant Alpha AI Agent Super Orchestrator Settings
@@ -147,20 +231,34 @@ ELEPHANT_ALPHA_PERFORMANCE_TRACKING=true
ELEPHANT_ALPHA_AUTO_ESCALATION_ENABLED=true
# Integration Settings
ELEPHANT_ALPHA_HERMES_URL=http://192.168.0.111:11434
ELEPHANT_ALPHA_HERMES_URL=
ELEPHANT_ALPHA_HERMES_MODEL=hermes3:latest
ELEPHANT_ALPHA_NEMOTRON_NIM_ENDPOINT=https://integrate.api.nvidia.com/v1
ELEPHANT_ALPHA_URL=https://integrate.api.nvidia.com/v1/chat/completions
ELEPHANT_ALPHA_OPENCLAW_GEMINI_ENDPOINT=https://generativelanguage.googleapis.com/v1beta
# ── Google Gemini API ───────────────────────────────────────────────────────
# OpenClaw 策略師 / MCP Collector / Code Review Pipeline 共用金鑰
# ── Google Gemini API(僅備援 / 鎖定場景)────────────────────────────────────
# Gemini 只能作為 Ollama 失敗備援或 ADR-028 鎖定場景,不可設為通用預設 provider
# 取得方式https://aistudio.google.com/app/apikey
# 注意Gemini 2.0 Flash 將於 2026-06-01 關閉,後續需遷移至 2.5 Flash
# 預設硬關閉:即使 GEMINI_API_KEY 存在、fallback flag 被誤開,也不會出站產生費用
GEMINI_API_HARD_DISABLED=true
GEMINI_FALLBACK_ENABLED=false
GEMINI_ALLOWED_CONTEXTS=
GEMINI_API_KEY=<change-me>
GEMINI_MODEL=gemini-1.5-flash
OPENCLAW_MODEL=gemini-2.5-flash-preview-05-20
# ── Anthropic Claude APIPhase 7 Frontier 升級)───────────────────────────
# 用途Code Review 的 Ollama-first 主路徑失敗後,可選擇 Claude Opus 4.7 作雲端備援
# 取得方式https://console.anthropic.com/settings/keys
# feature flag CODE_REVIEW_USE_CLAUDE 預設 false即使設 true 也必須先跑 Ollama 三主機
# 啟用備援步驟:(1) 設 ANTHROPIC_API_KEY (2) CODE_REVIEW_USE_CLAUDE=true
ANTHROPIC_API_KEY=
CODE_REVIEW_USE_CLAUDE=false
CLAUDE_MODEL=claude-opus-4-7
CLAUDE_TIMEOUT=120
# Debug and Monitoring
ELEPHANT_ALPHA_DEBUG_MODE=false
ELEPHANT_ALPHA_METRICS_ENABLED=true
@@ -183,18 +281,35 @@ INITIAL_ADMIN_PASSWORD=your_initial_admin_password_here
# 不設則所有 /bot/api/* 端點拒絕請求
BOT_API_TOKEN=your_bot_api_token_here
# [填] Post-deploy AI code review pipeline 自動修復開關
CODE_REVIEW_AUTO_FIX_ENABLED=false
# [填] Post-deploy AI code review pipeline 自動修復開關
# ADR-020 規定預設 true任何 finding 一律自動觸發 AiderHeal安全網=Git+CI/CD 回滾)
# 僅在需要短期關閉自動修復鏈時設為 false
CODE_REVIEW_OLLAMA_MODEL=qwen2.5-coder:7b
CODE_REVIEW_OLLAMA_TIMEOUT=15
CODE_REVIEW_OLLAMA_SECONDARY_MODEL=gemma3:4b
CODE_REVIEW_OLLAMA_SECONDARY_TIMEOUT=60
CODE_REVIEW_OLLAMA_FALLBACK_MODEL=hermes3:latest
CODE_REVIEW_OLLAMA_FALLBACK_TIMEOUT=20
CODE_REVIEW_OLLAMA_NUM_PREDICT=384
CODE_REVIEW_OLLAMA_KEEP_ALIVE=5m
# 預設保護 111Code Review 這類部署後重分析只跑 GCP-A/GCP-B需明確救急才設 true。
CODE_REVIEW_ALLOW_111_FALLBACK=false
CODE_REVIEW_HERMES_TIMEOUT=35
CODE_REVIEW_HERMES_PRIMARY_MODEL=qwen2.5-coder:7b
CODE_REVIEW_HERMES_PRIMARY_TIMEOUT=15
CODE_REVIEW_HERMES_SECONDARY_MODEL=gemma3:4b
CODE_REVIEW_HERMES_SECONDARY_TIMEOUT=45
CODE_REVIEW_HERMES_FALLBACK_MODEL=hermes3:latest
CODE_REVIEW_HERMES_FALLBACK_TIMEOUT=20
CODE_REVIEW_HERMES_NUM_PREDICT=384
CODE_REVIEW_HERMES_MAX_FILES=2
CODE_REVIEW_HERMES_MAX_CHARS=900
CODE_REVIEW_HERMES_LLM_SCAN_ENABLED=false
CODE_REVIEW_AUTO_FIX_ENABLED=true
# [選填] 僅本機開發可設 true正式環境不得允許不安全 internal webhook
MOMO_ALLOW_INSECURE_INTERNAL_WEBHOOK_FOR_DEV=false
# [選填] AIOps SSH Jump 跳板設定services/jump_executor.py
SSH_JUMP_HOST=192.168.0.110
SSH_JUMP_USER=wooo
SSH_TARGET_HOST=192.168.0.188
SSH_TARGET_USER=ollama
# ──────────────────────────────────────────────────────────────────────────
# AIOps / Autonomous Code RepairADR-014
# ──────────────────────────────────────────────────────────────────────────
@@ -210,9 +325,9 @@ DEPLOY_SSH_KEY_PATH=/home/wooo/.ssh/id_ed25519
# [選填] 110 主機上的 repo 路徑
AIDER_REPO_PATH=/home/wooo/ewoooc
# [選填] Aider 使用的模型與 Ollama API endpoint
# [選填] Aider 使用的模型與 Ollama API endpoint;留空時自動走 GCP-A → GCP-B → 111
AIDER_MODEL=ollama/qwen2.5-coder:7b
OLLAMA_API_BASE=http://192.168.0.111:11434
OLLAMA_API_BASE=
# [選填] 自動修復安全閥
AIDER_MAX_DIFF_LINES=50
@@ -257,23 +372,120 @@ MOMO_AI_AUTOMATION_SMOKE_HISTORY_LIMIT=200
# [選填] OpenClaw Telegram bot
OPENCLAW_BOT_TOKEN=your_openclaw_bot_token_here
TELEGRAM_BOT_USERNAME=@OpenClawAwoooI_Bot
OPENCLAW_BOT_USERNAME=@OpenClawAwoooI_Bot
OPENCLAW_GROUP_ID=-1003940688311
OPENCLAW_ALLOWED_USERS=
OPENCLAW_ADMIN_USER_IDS=
# [預設 1] 舊行為:空白名單仍允許私訊;正式環境建議設 0 並填 OPENCLAW_ALLOWED_USERS
OPENCLAW_ALLOW_PRIVATE_WITHOUT_WHITELIST=1
# [預設 24] PPT 報表快取保留時間(小時)
OPENCLAW_PPT_CACHE_TTL_HOURS=24
# [預設 OFF] ADR-019 agent dispatch啟用後只讓白名單 cmd 轉 NL agent 處理
OPENCLAW_AGENT_DISPATCH=0
OPENCLAW_AGENT_DISPATCH_CMDS=sales,top,vendor
# [選填] AI provider 選擇與外部資料源
# [選填] AI provider 選擇與外部資料源Gemini 不可設為預設,只能當 Ollama 備援
AI_PROVIDER=ollama
YOUTUBE_API_KEY=
GEMINI_TIMEOUT=60
# [預設 OFF] AI runtime feature flags未完成部署驗收前不要在正式環境打開
AI_CALL_LOGGING_ENABLED=true
MODEL_ROUTER_ENABLED=false
COST_THROTTLE_ENABLED=false
COST_THROTTLE_PROJECT_RATIO=1.10
COST_UNTHROTTLE_PROJECT_RATIO=0.95
RAG_ENABLED=false
RAG_DEFAULT_THRESHOLD=0.85
RAG_DEFAULT_TOP_K=5
RAG_EMBED_MODEL=bge-m3:latest
RAG_EMBED_DIM=1024
RAG_EMBED_NORMALIZE=true
EMBED_CONSISTENCY_INCLUDE_111=false
PPT_VISION_ENABLED=true
PPT_VISION_MODEL=minicpm-v:latest
PPT_VISION_TIMEOUT=120
PPT_VISION_MAX_SLIDES=1
PPT_AUTO_GENERATION_ENABLED=true
PPT_AUTO_REPORT_TYPES=all
PPT_AUTO_DEFAULT_CATEGORY=美妝保養
DEEPSEEK_DIRECT_ENABLED=false
DEEPSEEK_API_KEY=
DEEPSEEK_BASE_URL=https://api.deepseek.com/v1
DEEPSEEK_MODEL=deepseek-chat
DEEPSEEK_TIMEOUT=60
OPENCLAW_DAILY_HERMES_TEMPLATE=true
OPENCLAW_OLLAMA_MODEL=qwen2.5-coder:7b
PROMOTION_PENDING_BATCH_SIZE=50
AWAITING_REVIEW_PUSH_BATCH=5
TELEGRAM_ADMIN_CHAT_ID=
# ──────────────────────────────────────────────────────────────────────────
# Ollama / MCP / 密碼政策
# ──────────────────────────────────────────────────────────────────────────
OLLAMA_HOST=https://ollama.wooo.work/ollama
OLLAMA_HOST=
OLLAMA_HOST_PRIMARY=http://34.87.90.216:11434
OLLAMA_HOST_SECONDARY=http://34.21.145.224:11434
OLLAMA_HOST_FALLBACK=http://192.168.0.111:11434
OLLAMA_HOST_PRIMARY_PROXY=http://192.168.0.110:11435
OLLAMA_HOST_SECONDARY_PROXY=http://192.168.0.110:11436
OLLAMA_RESOLVE_HOST_HEALTH_SKIP_ENABLED=true
OLLAMA_RESOLVE_HOST_HEALTH_SKIP_WINDOW_MINUTES=20
OLLAMA_MODEL=gemma3:4b
OLLAMA_TIMEOUT=120
OLLAMA_COPY_TIMEOUT=180
OLLAMA_EMBED_TIMEOUT=45
OLLAMA_EMBED_TIMEOUT=30
OLLAMA_EMBED_MAX_TIMEOUT=30
OLLAMA_EMBED_KEEP_ALIVE=1m
OLLAMA_EMBED_MAX_CHARS=4000
OLLAMA_EMBED_GCP_FAILURE_COOLDOWN_SEC=60
OLLAMA_EMBED_GCP_FAILURE_NOTICE_SEC=30
OLLAMA_EMBED_HOST_HEALTH_SKIP_ENABLED=true
OLLAMA_EMBED_HOST_HEALTH_SKIP_WINDOW_MINUTES=20
OLLAMA_HOST_HEALTH_MODEL_PROBE_ENABLED=true
OLLAMA_HOST_HEALTH_MODEL_PROBE_INCLUDE_111=false
OLLAMA_HOST_HEALTH_EMBED_MODEL=bge-m3:latest
OLLAMA_HOST_HEALTH_EMBED_TIMEOUT=30
OLLAMA_HOST_HEALTH_EMBED_KEEP_ALIVE=1m
# 111 是 Mac final fallback不承接 7B+ / vision / long-context / 長輸出任務;落到 111 時自動降級與縮短常駐。
OLLAMA_111_MODEL_FALLBACK=llama3.2:latest
OLLAMA_111_MODEL_DOWNGRADE_PATTERNS=qwen3:*,deepseek-r1:*,hermes3:*,llama3.1:*,qwen2.5:*,qwen2.5-coder:*,gemma3:*,minicpm-v:*,llava:*,*:7b*,*:8b*,*:14b*,*:32b*,*:70b*
OLLAMA_111_KEEP_ALIVE=5m
OLLAMA_111_MAX_TIMEOUT=20
OLLAMA_111_NUM_CTX=4096
OLLAMA_111_NUM_PREDICT=512
# [預設 true] OpenClaw Q&A 先走 Ollama品質不足或失敗時才 fallback Gemini/NIM
# 主機不提供單 caller override一律走 OLLAMA_HOST_PRIMARY → OLLAMA_HOST_SECONDARY → OLLAMA_HOST_FALLBACK
OPENCLAW_QA_OLLAMA_FIRST=true
OPENCLAW_QA_OLLAMA_MODEL=qwen3:14b
OPENCLAW_QA_OLLAMA_TIMEOUT=60
OPENCLAW_IMAGE_VISION_MODEL=minicpm-v:latest
OPENCLAW_IMAGE_OLLAMA_TIMEOUT=45
OPENCLAW_IMAGE_GEMINI_MODEL=gemini-1.5-flash
NEMOTRON_OLLAMA_FIRST=true
NEMOTRON_OLLAMA_MODEL=qwen3:14b
NEMOTRON_OLLAMA_TIMEOUT=180
OPENCLAW_STRATEGY_OLLAMA_MODEL=qwen3:14b
OPENCLAW_STRATEGY_OLLAMA_TIMEOUT=90
OPENCLAW_STRATEGY_OLLAMA_NUM_PREDICT=2048
OPENCLAW_STRATEGY_OLLAMA_KEEP_ALIVE=5m
# [預設 OFF] MCP Router需先部署 docker-compose.mcp.yml 並完成健康檢查再開
MCP_ROUTER_ENABLED=false
MCP_POSTGRES_URL=http://127.0.0.1:3001
MCP_FIRECRAWL_URL=http://127.0.0.1:3002
MCP_OMNISEARCH_URL=http://127.0.0.1:3003
MCP_FILESYSTEM_URL=http://127.0.0.1:3004
MCP_POSTGRES_PASSWORD=your_mcp_readonly_password_here
TAVILY_API_KEY=
EXA_API_KEY=
FIRECRAWL_AUTH_KEY=momo-internal-only
MCP_TIMEOUT_SEC=30
MCP_CACHE_TTL_SEC=3600
MCP_MAX_RESULT_BYTES=65536
MCP_CACHE_TTL_HOURS=24
MCP_GEMINI_MODEL=gemini-2.0-flash
@@ -289,18 +501,77 @@ PASSWORD_EXPIRY_DAYS=90
# 備份 / 報表 / 同步
# ──────────────────────────────────────────────────────────────────────────
DATA_DIR=/app/data
BACKUP_DIR=/app/data/db_backups
BACKUP_RETENTION_DAYS=7
DB_CONTAINER=momo-db
REPORTS_DIR=/app/data/reports
DATABASE_PATH=data/momo_database.db
SQLITE_PATH=/app/data/momo_database.db
PG_SYNC_ENABLED=false
PG_SYNC_INTERVAL=300
# PChome 競品比價與補抓產線
COMPETITOR_INTEL_CACHE_TTL_SECONDS=21600
PCHOME_FEEDER_TIMEOUT=12
PCHOME_FEEDER_RATE_DELAY=1.0
PCHOME_FEEDER_SEARCH_LIMIT=20
PCHOME_FEEDER_MAX_SEARCH_TERMS=6
PCHOME_FEEDER_SEARCH_MAX_PAGES=2
PCHOME_FEEDER_SEARCH_COVERAGE_RESCUE_ENABLED=true
# browse.sh 只作低信心/無結果的診斷計畫;正式排程預設不自動開瀏覽器。
PCHOME_FEEDER_BROWSE_SH_DIAGNOSTIC_ENABLED=true
PCHOME_FEEDER_BROWSE_SH_EXECUTE_ENABLED=false
PCHOME_FEEDER_BROWSE_SH_TIMEOUT=20
PCHOME_FEEDER_BROWSE_SH_MAX_PER_RUN=3
PCHOME_FEEDER_BROWSE_SH_OUTPUT_PREVIEW_CHARS=1200
PCHOME_BACKFILL_STATUS_PATH=/app/data/pchome_match_backfill_status.json
PCHOME_BACKFILL_ACTIVE_TTL_SECONDS=7200
# PPT 預覽與視覺 QA
PPT_PREVIEW_CACHE_DIR=/app/data/ppt_previews
PPT_VISION_STATE_PATH=/app/data/ppt_vision_audit_status.json
PPT_VISION_ACTIVE_TTL_SECONDS=7200
PPT_VISION_IMAGE_MAX_EDGE=1280
PPT_VISION_IMAGE_QUALITY=82
# Action plan hygiene / ElephantAlpha resource policy
ACTION_PLAN_HYGIENE_STALE_HOURS=24
ACTION_PLAN_HYGIENE_MAX_UPDATES=200
ELEPHANT_ALPHA_RESOURCE_QUEUE_THRESHOLD=10
ELEPHANT_ALPHA_RESOURCE_LOAD_THRESHOLD_PCT=80
ELEPHANT_ALPHA_RESOURCE_HIGH_PRIORITY_THRESHOLD=5
ELEPHANT_ALPHA_RESOURCE_STALE_THRESHOLD=5
ELEPHANT_ALPHA_RESOURCE_STALE_HOURS=24
ELEPHANT_ALPHA_RESOURCE_HYGIENE_ENABLED=true
ELEPHANT_ALPHA_HERMES_LLM_PREFETCH_ENABLED=false
# [選填] 外部 BI 連結(模板全域變數)
METABASE_URL=https://mo.wooo.work/metabase
GRIST_URL=https://grist.wooo.work
GRIST_URL=https://mo.wooo.work/grist
MB_SITE_URL=https://mo.wooo.work/metabase
GRIST_APP_HOME_URL=https://mo.wooo.work/grist
GRIST_ADMIN_EMAIL=admin@wooo.work
GRAFANA_PASSWORD=change-me
PGADMIN_EMAIL=admin@wooo.work
PGADMIN_PASSWORD=change-me
SUPERSET_SECRET_KEY=change-me
# ──────────────────────────────────────────────────────────────────────────
# 部署 / CI / smoke test 輔助變數
# ──────────────────────────────────────────────────────────────────────────
PROD_BASE_URL=https://mo.wooo.work
SSH_JUMP_HOST=192.168.0.110
SSH_JUMP_USER=wooo
SSH_TARGET_HOST=192.168.0.188
SSH_TARGET_USER=ollama
GITHUB_OUTPUT=
SKIP_FEEDER=false
SKIP_HERMES=false
SKIP_NIM=false
SKIP_TELEGRAM=false
# ──────────────────────────────────────────────────────────────────────────
# n8n Workflow Automationmonitoring profile

View File

@@ -46,6 +46,8 @@ on:
- '.claude/**'
# 工作流程本身
- '.gitea/workflows/**'
# DB schema 變更Operation Ollama-First v5.0 P1CD 自動 apply migration
- 'migrations/**'
# docs/、memory/、ADR、k8s/ 等不觸發
workflow_dispatch:
inputs:
@@ -74,6 +76,8 @@ jobs:
run: |
echo "short_sha=${GITHUB_SHA::7}" >> $GITHUB_OUTPUT
echo "message=$(git log -1 --pretty=%s | head -c 60)" >> $GITHUB_OUTPUT
VERSION=$(sed -n "s/^SYSTEM_VERSION[[:space:]]*=[[:space:]]*[\"']\([^\"']*\)[\"'].*/\1/p" config.py | head -1)
echo "version=$VERSION" >> $GITHUB_OUTPUT
echo "start_time=$(date +%s)" >> $GITHUB_OUTPUT
# 偵測是否需重建 Docker imageforce_rebuild 優先,其次看變更檔案)
@@ -91,7 +95,19 @@ jobs:
echo "label=🔨 重建 Docker Image" >> $GITHUB_OUTPUT
else
echo "type=sync" >> $GITHUB_OUTPUT
echo "label=📁 同步 Python 檔案" >> $GITHUB_OUTPUT
echo "label=📁 同步 runtime 檔案" >> $GITHUB_OUTPUT
fi
- name: 偵測 AI 觀測台前端 QA 是否需要執行
id: observability_qa
run: |
CHANGED=$(git diff --name-only HEAD~1 HEAD 2>/dev/null || echo "")
echo "$CHANGED"
printf '%s\n' "$CHANGED" | python3 scripts/check_observability_deploy_gate.py --stdin --github-output "$GITHUB_OUTPUT"
if grep -q '^needed=true$' "$GITHUB_OUTPUT"; then
echo "🎛️ AI 觀測台 QA: required"
else
echo " AI 觀測台 QA: skipped"
fi
# 設定 SSH 金鑰 + 主機驗證C2 fix: 移除 StrictHostKeyChecking no
@@ -142,6 +158,12 @@ jobs:
run: |
apt-get update -qq && apt-get install -y -qq rsync openssh-client
- name: AI 觀測台 Pre-deploy 靜態 QA
if: steps.observability_qa.outputs.needed == 'true'
run: |
bash ./scripts/quick_review.sh --check-observability-css
bash ./scripts/quick_review.sh --observability-qa --skip-production
# ── 模式 A僅同步 Python 檔案(最常見,~10s ────────────────────────
- name: 同步 Python 檔案至 188
if: steps.deploy_type.outputs.type == 'sync'
@@ -173,6 +195,41 @@ jobs:
--exclude='._*' \
./ ollama@192.168.0.188:/home/ollama/momo-pro/ || true
# ── Operation Ollama-First v5.0 P1自動 apply pending migration ─────
# HOTFIX (2026-05-04 Telegram 報「ai_calls relation does not exist」):
# 原邏輯 git diff HEAD~1 HEAD 只看單一 commit但 v5.0 migrations 024-028 在 commit
# 4648673早期後續 push 都不含 migration → 從未被 CD 跑過。
# 改邏輯:跑 v5.0 戰役所有 migrations024-099 編號範圍)。
# 安全保證:所有 v5.0 migration 都是 IF NOT EXISTS / WHERE NOT EXISTS / CREATE EXTENSION IF NOT EXISTS
# 重跑 100% 冪等無害critic-A11 修補保證)。
- name: 套用 v5.0 戰役 migration024-099 範圍,冪等)
if: steps.deploy_type.outputs.type == 'sync' || steps.deploy_type.outputs.type == 'rebuild'
run: |
ssh -i ~/.ssh/id_deploy ollama@192.168.0.188 '
set -e
cd /home/ollama/momo-pro
# v5.0 戰役 migration 編號 024+ 全部冪等
V5_MIGRATIONS=$(ls migrations/02[4-9]_*.sql migrations/03[0-9]_*.sql migrations/04[0-9]_*.sql migrations/05[0-9]_*.sql migrations/06[0-9]_*.sql migrations/07[0-9]_*.sql migrations/08[0-9]_*.sql migrations/09[0-9]_*.sql 2>/dev/null | sort | uniq || true)
if [ -z "$V5_MIGRATIONS" ]; then
echo " 無 v5.0 migration 檔案"
exit 0
fi
echo "🗄️ v5.0 戰役 migrations 全部跑(冪等 IF NOT EXISTS 保證):"
echo "$V5_MIGRATIONS"
for m in $V5_MIGRATIONS; do
echo "▶️ Applying $m"
# CONCURRENTLY 不能包 -1 transaction
if grep -q "CONCURRENTLY" "$m"; then
docker exec -i momo-db psql -U momo -d momo_pro < "$m" 2>&1 | tail -5 || \
echo "⚠️ $m apply 警告IF NOT EXISTS 冪等可忽略)"
else
docker exec -i momo-db psql -U momo -d momo_pro -1 < "$m" 2>&1 | tail -5 || \
echo "⚠️ $m apply 警告IF NOT EXISTS 冪等可忽略)"
fi
done
echo "✅ v5.0 migration apply 階段完成"
'
- name: 重啟容器Sync 模式)
if: steps.deploy_type.outputs.type == 'sync'
run: |
@@ -254,8 +311,13 @@ jobs:
echo " Monitoring 設定未變更,略過重新載入"
fi
# ── 健康檢查H3: HTTP + 三容器狀態雙重驗證) ─────────────────────────
# ── 健康檢查H3: HTTP + 三容器 + Phase 34 SPA Shadow 偵測) ──────────
- name: 健康檢查
env:
COMMIT_SHA: ${{ steps.commit.outputs.short_sha }}
EXPECTED_VERSION: ${{ steps.commit.outputs.version }}
TELEGRAM_BOT_TOKEN: ${{ secrets.TELEGRAM_BOT_TOKEN }}
TELEGRAM_CHAT_ID: ${{ secrets.TELEGRAM_CHAT_ID }}
run: |
echo "⏳ 等待服務啟動30s..."
sleep 30
@@ -273,6 +335,14 @@ jobs:
[ "$i" -eq 12 ] && echo "❌ HTTP 健康檢查失敗" && exit 1
sleep 15
done
EXTERNAL_HEALTH=$(curl -fsS --max-time 10 https://mo.wooo.work/health)
EXTERNAL_VERSION=$(python3 -c "import json,sys; print(json.load(sys.stdin).get('version',''))" <<< "$EXTERNAL_HEALTH")
if [ "$EXTERNAL_VERSION" != "$EXPECTED_VERSION" ]; then
echo "❌ 正式版本未更新expected=$EXPECTED_VERSION actual=$EXTERNAL_VERSION"
echo "$EXTERNAL_HEALTH"
exit 1
fi
echo "✅ 正式版本驗證通過:$EXTERNAL_VERSION"
# 驗證三應用容器均在 Running 狀態
ssh -i ~/.ssh/id_deploy ollama@192.168.0.188 \
'RUNNING=$(docker ps --format "{{.Names}}" | grep -cE "momo-(pro-system|scheduler|telegram-bot)" || true); \
@@ -283,6 +353,47 @@ jobs:
echo "✅ 三容器均正常運行($RUNNING/3"; \
fi'
# ── Phase 34 SPA Shadow 偵測 — 防 nginx fallback 偽綠 ───────────────
# 過去 5 個 deployrun 273-277全 success 但 prod 上 Flask 從未接到請求,
# 因為 nginx 對 /admin/* 等路徑全 fallback 到 SPA index.html7480 byte
# 三條 fingerprint 任一不符 SPA = Flask 真接到:
# (a) Content-Length != 7480
# (b) etag != e167a58a1baf907f55a2925a2e8665d1
# (c) x-process-time header 存在Flask middleware
echo "🔍 SPA Shadow 偵測(驗 Flask 真接到請求)..."
SPA_ETAG='e167a58a1baf907f55a2925a2e8665d1'
SPA_LEN='7480'
# 用 /health純 Flask不會被 SPA 路徑攔)做基準探針
HDR=$(curl -sS -D - -o /dev/null --max-time 10 https://mo.wooo.work/health 2>/dev/null || echo "")
# P37: grep 沒匹配返回 1pipefail+set -e 會殺整段腳本 — 全部加 || true
ETAG=$(echo "$HDR" | grep -i '^etag:' 2>/dev/null | tr -d '"\r' | awk '{print $2}' | tr 'A-Z' 'a-z' || true)
CLEN=$(echo "$HDR" | grep -i '^content-length:' 2>/dev/null | awk '{print $2}' | tr -d '\r' || true)
XPT=$(echo "$HDR" | grep -i '^x-process-time:' 2>/dev/null | awk '{print $2}' | tr -d '\r' || true)
FLASK_OK=0
# P36 修:用 if/then 而非 && 串連,避免 bash -e 在第一條 false 就 exit
if [ -n "$XPT" ] && [ "$XPT" != "0" ] && [ "$XPT" != "0.0" ]; then FLASK_OK=1; fi
if [ -n "$ETAG" ] && [ "$ETAG" != "$SPA_ETAG" ]; then FLASK_OK=1; fi
if [ -n "$CLEN" ] && [ "$CLEN" != "$SPA_LEN" ]; then FLASK_OK=1; fi
if [ "$FLASK_OK" != "1" ]; then
echo "❌ SPA Shadow 偵測:/health 看似 200 但 nginx fallback 攔截"
echo " etag=$ETAG (SPA=$SPA_ETAG)"
echo " content-length=$CLEN (SPA=$SPA_LEN)"
echo " x-process-time=$XPT Flask 應 > 0"
# Telegram 告警(如 secrets 已設)
if [ -n "${TELEGRAM_BOT_TOKEN}" ] && [ -n "${TELEGRAM_CHAT_ID}" ]; then
MSG="🚨 EwoooC SPA Shadow 偵測警告%0A├ commit ${COMMIT_SHA}%0A├ /health 被 nginx SPA fallback 攔截%0A└ 立即查 nginx upstream / Flask container"
curl -sS -m 5 -X POST "https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/sendMessage" \
-d "chat_id=${TELEGRAM_CHAT_ID}" -d "text=${MSG}" -d "parse_mode=HTML" >/dev/null || true
fi
exit 1
fi
echo "✅ SPA Shadow OK — Flask 真接到請求etag=$ETAG xpt=$XPT clen=$CLEN"
- name: AI 觀測台 Post-deploy Production QA
if: success() && steps.observability_qa.outputs.needed == 'true'
run: |
bash ./scripts/quick_review.sh --observability-smoke --base-url https://mo.wooo.work --timeout 12
# ── 觸發 Post-Deploy Code Review ─────────────────────────────────────
- name: 觸發 AI Code Review
if: success()

26
.gitignore vendored
View File

@@ -9,6 +9,9 @@
# Claude Code 本機設定(含 allow list / Secret不可 commit
.claude/settings.local.json
.claude/worktrees/
.tmp_*
tmp_*.png
# Python
__pycache__/
@@ -63,6 +66,8 @@ data/*.db-wal
data/*.sqlite
data/*.sqlite3
data/*.lock
data/ppt_vision_audit_status.json
data/*.pkl
database/*.db
database/*.db-journal
database/*.db-shm
@@ -82,11 +87,32 @@ data/excel_exports/
*.xlsx~
~$*.xlsx
# 本機 QA / 頁面快取
data/*_cache/
data/ai_automation_smoke_history.jsonl
# 上傳檔案
web/static/uploads/
web/static/screenshots/
uploads/
screenshots/
MOMO Pro/uploads/
MOMO Pro/screenshots/
templates/__init__.py
# 本機前端設計稿 / 產生式 prototype sandbox未整合前不進版本庫
MOMO Pro/
production_v3*/
frontend/
docker-compose.frontend.yml
# 生成式設計審計 / handoff dump正式治理以 docs/memory/frontend_v3_handoff_20260512.md 為索引)
docs/design/
docs/design_audit_frontend/
# 本機觀測台 macro prototype未被任何模板 import 前不入庫)
templates/components/_observability_macros.html
# 測試與覆蓋率報告
.pytest_cache/
.coverage

27
110-ollama-proxy.conf Normal file
View File

@@ -0,0 +1,27 @@
# 110 Ollama GCP Proxy — ADR-028 三主機級聯轉發
server {
listen 11435;
location / {
proxy_pass http://34.87.90.216:11434;
proxy_connect_timeout 10s;
proxy_send_timeout 300s;
proxy_read_timeout 300s;
proxy_buffering off;
}
location /nginx-health {
return 200 "Ollama GCP-A Proxy OK\n";
}
}
server {
listen 11436;
location / {
proxy_pass http://34.21.145.224:11434;
proxy_connect_timeout 10s;
proxy_send_timeout 300s;
proxy_read_timeout 300s;
proxy_buffering off;
}
location /nginx-health {
return 200 "Ollama GCP-B Proxy OK\n";
}
}

View File

@@ -107,7 +107,9 @@
| 主機 | IP | 角色 |
|---|---|---|
| 110 | `192.168.0.110` | Gateway、Nginx、Gitea、n8n、Superset |
| 188 | `192.168.0.188` | App、DB、Ollama、生產容器 |
| 188 | `192.168.0.188` | App、DB、生產容器、AutoHeal target不可作為 Ollama 節點) |
| GCP-SSD-1 | `34.87.90.216` | Primary Ollama (High Performance SSD, All Models) |
| GCP-SSD-2 | `34.21.145.224` | Secondary Ollama (SSD Optimized, Redundancy) |
## 6. 核心服務
@@ -127,6 +129,7 @@
- `gunicorn.conf.py` 必須透過 `docker-compose.yml` bind mount 進 `momo-app`;除救急外,不以 `docker cp` 當常態部署方式。
- CD rebuild 應先完成 image build再短暫 recreate 三應用容器;禁止把 no-cache build 時間變成長時間 502。
- HTTP health / Blackbox / CD 探測必須打 `/health`,不可打 Dashboard 首頁 `/`,避免監控流量觸發重型查詢造成 worker starvation。
- 所有 AI Agent / LLM / embedding 呼叫必須 Ollama-first且只允許 GCP-A `34.87.90.216:11434` → GCP-B `34.21.145.224:11434` → 111 `192.168.0.111:11434` 三主機級聯Gemini 只能作為備援或 ADR-028 鎖定場景,且預設由 `GEMINI_API_HARD_DISABLED=true` 硬封鎖188 不可作為 Ollama 節點。
## 8. 常用入口
@@ -134,7 +137,11 @@
- DevOps 手冊: `docs/guides/devops_handbook.md`
- 模組化治理: `docs/guides/modularization_governance.md`
- 前端更版路線圖: `docs/guides/frontend_upgrade_roadmap.md`
- AI 觀測台 UI 治理: `docs/guides/observability_ui_governance.md`
- AI 自動化 Session SOP: `docs/guides/ai_automation_session_sop.md`
- Browse.sh 爬蟲診斷手冊: `docs/guides/browse_sh_crawler_playbook.md`
- Webcrumbs 共用 UI Runtime: `docs/guides/webcrumbs_shared_runtime.md`
- 外部專業 Benchmark: `docs/guides/external_professional_benchmark.md`
- AI 競價情報 SOT: `docs/AI_INTELLIGENCE_MODULE_SOT.md`
- Agent 角色矩陣: `docs/guides/codex_agent_roles.md`
- ADR 索引: `docs/adr/README.md`
@@ -142,6 +149,7 @@
- 歷史紀錄: `docs/memory/history_logs.md`
- 程式碼模組化盤點: `docs/memory/code_modularization_inventory_20260430.md`
- AI 自動化閉環記憶: `docs/memory/ai_automation_closure_20260429.md`
- AI 觀測台 UI QA 記憶: `docs/memory/observability_ui_qa_guardrails_20260505.md`
- 憑證手冊: `docs/memory/credentials_passbook.md`
## 9. 常用指令
@@ -149,6 +157,8 @@
```bash
source venv/bin/activate && python app.py
git push origin main
./scripts/quick_review.sh --sync-observability-css
./scripts/quick_review.sh --observability-qa
ssh wooo@192.168.0.110 "ssh ollama@192.168.0.188 \"docker ps --format '{{.Names}} | {{.Status}}' | grep momo-; docker exec momo-scheduler env | grep -iE 'TELEGRAM|NVIDIA'; docker logs momo-scheduler --since 1h | grep -E 'Telegram|Error' | tail -10\""
ssh wooo@192.168.0.110 "ssh ollama@192.168.0.188 \"cd /home/ollama/momo-pro && docker compose up -d --no-deps --force-recreate <service>\""
```

View File

@@ -140,6 +140,12 @@
- ❌ **禁止**: 使用 mock data、假商品、假 KPI、假排程、假使用者、假頁面或純展示用 placeholder 冒充已完成。
- ❌ **禁止**: 為了符合原型畫面而改寫或捏造業務數字。
### 第 14.2 條:前端文案與工作溝通隔離(絕對禁止違反)
- ✅ **正確**: 前端頁面只放使用者完成任務所需的產品文案、狀態、操作入口與可診斷錯誤。
- ✅ **正確**: 施工紀錄、版本發布說明、AI 工作視窗判斷、Session 溝通、TODO 內容,只能放在文件、日誌或提交訊息,不得搬到使用者可見頁面。
- ❌ **禁止**: 在模板、靜態 JS/CSS 可見文案中放入「本輪已完成」「剛剛修正」「Codex/Claude 評估」「V10.x hotfix」「推到 Gitea」等工作視窗溝通內容。
- ❌ **禁止**: 用內部工程語氣代替產品語氣,例如把頁面寫成施工報告、交接紀錄或 agent 工作摘要。
---
## 第五章:系統架構規範
@@ -169,12 +175,22 @@
- ✅ **正確**: Gunicorn runtime 必須保留可併發回應輕量 health check 的 worker 設定,例如 `gthread` + `GUNICORN_THREADS`。
- ❌ **禁止**: 用會觸發大量 DB 查詢或模板渲染的頁面作為探測目標,避免監控流量本身造成 worker starvation。
### 第 18.2 條AI / LLM 路由主機紅線(絕對禁止違反)
- ✅ **正確**: 所有 AI Agent、LLM 推理與 embedding 預設必須走 Ollama 三主機級聯GCP-A `34.87.90.216:11434` → GCP-B `34.21.145.224:11434` → 111 `192.168.0.111:11434`。
- ✅ **正確**: 所有通用文字生成、Q&A 第一響應、Hermes、NemoTron qwen3 路徑、AiderHeal 與 embedding 必須透過 `services/ollama_service.resolve_ollama_host()` 或同等核准 wrapper 取得主機。
- ✅ **正確**: Gemini 只能作為 Ollama 主路徑失敗後的備援,或 ADR-028 明確鎖定的低頻特殊場景。
- ✅ **正確**: `GEMINI_API_HARD_DISABLED` 預設必須為 `true``GEMINI_FALLBACK_ENABLED` 預設必須為 `false`;即使 `GEMINI_API_KEY` 存在,也不得出站呼叫 Gemini除非操作員明確解除 hard switch 並開啟緊急備援。
- ❌ **禁止**: 將 `AI_PROVIDER`、`OLLAMA_HOST`、`HERMES_URL`、`EMBEDDING_HOST`、`OLLAMA_API_BASE` 指向非 GCP-A / GCP-B / 111 的 Ollama 端點。
- ❌ **禁止**: 新增 Gemini-first 的 AI Agent、LLM caller 或把 Gemini 設為通用預設 provider新增 Gemini caller 必須走 ADR review。
- ❌ **禁止**: 繞過 `services.gemini_guard` 直接初始化 Gemini SDK 或直接用 `GEMINI_API_KEY` 打 Google Gemini REST API。
- ❌ **禁止**: 使用 188 主機作為 Ollama 節點188 只作為 App/DB/容器宿主與 AutoHeal target。
---
## 第六章:版本管理規範
### 第 19 條:版本號更新(強制要求)
- ✅ **正確**: 每次功能更新必須修改 `app.py` 的 `SYSTEM_VERSION`
- ✅ **正確**: 每次功能更新必須修改 `config.py` 的 `SYSTEM_VERSION``app.py` 僅從 config 匯入顯示。
- ✅ **格式**: `V主版本.次版本` (例如: V9.4)
- ❌ **禁止**: 修改功能但不更新版本號
@@ -332,9 +348,9 @@
## 第十三章AI 四 Agent 自主學習與自動化架構規範2026-04-29 修訂)
### 第 40 條:四 Agent 分工架構(絕對禁止違反)
- **Hermes採集層**: `192.168.0.111` Ollama,負責 embedding、去重、品質分數計算。成本 = $0
- **NemoTron處理層**: NVIDIA NIM Llama 3.1 8B負責 tool calling 邏輯路由與 DB 寫入。限額 80 次/天
- **OpenClaw / Gemini(應用層)**: 負責最終 PPT 生成、洞察報告對外輸出。成本最高,最後動用
- **Hermes採集層**: Ollama 三主機級聯GCP-A → GCP-B → 111,負責 embedding、去重、品質分數計算。成本 = $0
- **NemoTron處理層**: qwen3:14b Ollama-firstNVIDIA NIM Llama 3.1 8B 僅作備援,負責 tool calling 邏輯路由與 DB 寫入。NIM 限額 80 次/天
- **OpenClaw應用層**: Ollama-firstGemini 僅作備援或 ADR-028 鎖定場景,負責最終 PPT 生成、洞察報告對外輸出。
- **ElephantAlpha編排層**: 負責跨 Agent orchestration、HITL、AutoHeal bridge 與受控執行計畫,不可繞過安全入口
- ❌ **禁止**:讓 OpenClaw 做 Hermes 層的苦力工作(高算力浪費)
- ❌ **禁止**:讓 Hermes 直接生成對外報告(品質不足)
@@ -353,7 +369,7 @@
- **理由**:混合查詢(`WHERE` 結構化 + `ORDER BY embedding <->` 語意)只有 pgvector 能一條 SQL 搞定ADR-002
### 第 43 條Embedding 本地化(強制要求)
- ✅ **正確**:使用 `bge-m3`(或 `nomic-embed-text`)掛載在 Hermes 主機 `192.168.0.111` Ollama
- ✅ **正確**:使用 `bge-m3`(或 `nomic-embed-text`)掛載在 Ollama 三主機級聯GCP-A → GCP-B → 111
- ❌ **禁止**:呼叫外部 Embedding API成本與隱私雙重問題
- **維度**1024 dim`vector(1024)` 欄位ADR-003
@@ -450,7 +466,7 @@
|---------|------|------------|
| `config.py` | 系統配置 | `DATABASE_PATH`, `PUBLIC_URL` |
| `database/models.py` | 資料模型 | `Product.i_code` 定義 |
| `app.py` | 主程式 | `SYSTEM_VERSION`, `TAIPEI_TZ` |
| `app.py` | 主程式 | `TAIPEI_TZ` |
| `dashboard.html` | 商品看板 | 主題色系、響應式設計 |
| `daily_sales.html` | 業績看板 | 行事曆邏輯、圖表配置 |
| `scheduler.py` | 排程爬蟲 | 商品圖 CDN URL 構造 |

View File

@@ -10,6 +10,7 @@ RUN apt-get update && apt-get install -y \
g++ \
curl \
libpq-dev \
postgresql-client \
# Chrome/Selenium 依賴
wget \
gnupg \
@@ -30,6 +31,9 @@ RUN apt-get update && apt-get install -y \
libxrandr2 \
xdg-utils \
fonts-liberation \
fonts-noto-cjk \
fonts-noto-cjk-extra \
libreoffice-impress \
openssh-client \
libappindicator3-1 || true \
&& rm -rf /var/lib/apt/lists/*

View File

@@ -4,7 +4,7 @@
The system contains hardcoded database passwords in Kubernetes configuration files, which poses a security risk.
## Current Issues
1. **Hardcoded passwords**: `k8s/01-secrets.yaml` and `k8s/gcp/01-secrets.yaml` contain hardcoded password `"wooo_pg_2026"`
1. **Hardcoded passwords**: `k8s/01-secrets.yaml` and `k8s/gcp/01-secrets.yaml` contain hardcoded password `"<POSTGRES_PASSWORD>"`
2. **Missing environment configuration**: `.env.example` was missing database password configuration (now fixed)
## Security Recommendations
@@ -45,7 +45,7 @@ Replace hardcoded values in:
**Before (INSECURE):**
```yaml
stringData:
POSTGRES_PASSWORD: "wooo_pg_2026"
POSTGRES_PASSWORD: "<POSTGRES_PASSWORD>"
```
**After (SECURE):**

View File

@@ -38,8 +38,8 @@
```bash
# 1. 立即更換所有已外洩的憑證
# 當前已外洩的憑證包括:
# - LOGIN_PASSWORD: 0936223270
# - TELEGRAM_BOT_TOKEN: 8075645931:AAH-EGKMo8ZC4QJs-Nc1_0s92xHrGdQvdpg
# - LOGIN_PASSWORD: <LOGIN_PASSWORD>
# - TELEGRAM_BOT_TOKEN: <TELEGRAM_BOT_TOKEN>
# - LINE_CHANNEL_ACCESS_TOKEN
# - EMAIL_HOST_PASSWORD: jopokbhdpnnborjd
# - NGROK_AUTH_TOKEN: 36e27NM5V7sUJ8QxJIAAWCp7sUv_3brtcrBarYvcP3SbvFKhF

View File

@@ -1,4 +1,387 @@
================================================================================
前端 V3 守門落地 + FastAPI 重新評估 (2026-05-12) [IN PROGRESS]
================================================================================
【已完成】
- V10.601 收斂 Gemini / 111 治理與全 repo 已知密鑰清除:正式 `ai_calls` 近 24 小時與近 7 天 provider 彙總未見 Gemini 出站;舊 K8s manifest、n8n workflow、監控/auto-repair scripts、Superset 文件、Google Drive token 檔與歷史文件中的已知實密鑰全部改為占位符,並補測試禁止 Google API/OAuth key、Telegram token、Ollama Cloud key、Superset 預設密碼再次入庫OpenClaw 日/週/月/Meta 等敘事長報告改為 GCP-A/GCP-B only不再讓 `openclaw_meta` 在 GCP 超時後落到 111避免 111 被長文生成壓高負載。
- V10.600 收斂 AI Intelligence 競品表前台文案PChome 競品卡片 footer 不再顯示 `TTL: 6h`、比對門檻等工程參數,改為「僅顯示已通過身份比對的競品」;`identity_v2`、`match_type_exact`、`price_alert_exact`、`evidence_*`、`match_*` 等內部診斷 tag 只會轉成營運可讀的中文 badge未知 tag 直接隱藏,避免把 matcher 內部碼或實驗性標記露給使用者。
- V10.599 重整 PChome 比價覆核工作台 UX 並補全站巡檢能力:覆核頁不再沿用首頁商品表格,也不再把 `matcher_rescore`、`stored_status`、`rescore_accepted_current`、`HITL`、`COMPLETE` 等內部診斷/狀態碼輸出到前台或 tooltip改為「商品 / MOMO、PChome 候選、覆核判讀、下一步、紀錄」六欄工作流。同步修正 catalog review status 的前台語義、決策信封中文標籤、局部 1540px 橫向工作台、手機版欄位 label並把覆核狀態分段列改為自適應 grid避免 chip 造成桌面/平板/手機視覺溢出;`check_responsive_overflow.js` 改為逐頁輸出、HTTPS context、commit+body ready、timeout 後安全收尾,讓桌面/平板/手機全站 UX 巡檢可追蹤topbar AI 觀測台 indicator 增加前端 60 秒 session cache / 2.5 秒 abort 與後端 30 秒 cache避免每頁跳轉重複打 DB 查詢拖慢全站;`market_intel/disabled.html` 從 1MB 大型停用頁改為輕量狀態頁,保留狀態與正式操作入口,避免停用模組拖慢巡檢與使用者操作;新增憲法第 14.2 條與測試 guard禁止把工作視窗溝通、施工紀錄或版本發布說明放到使用者可見前端頁面ICAIM 競情 API 改為 120 秒短快取、5 秒 PostgreSQL statement timeout、stale 快照降級與 LATERAL 最新價查詢,避免 AI 競情看板重查詢拖慢全站。
- V10.584 補 PChome Nick 去重與 stale recovery 單品窄門:`Nick` 先去 HTML / 行銷星號 / 重複品名,避免 `29g`、`100ml` 被同一商品副標重複計數成 `component_count_conflict`;同步新增 NIVEA 妮維雅霜 100ml、Schick 舒綺敏感肌除毛刀片 3 入、TS6 沁涼潔淨慕斯 100g 的具名 exact total-price alignment。IBL 沐浴精+洗髮精 vs 洗髮精仍保留 identity review唇釉色號/目錄款與 Paula's Choice 效期/金蓋差異仍不自動寫正式價差。
- V10.583 補 Paula's Choice 身體乳 PChome Nick 具名 alignment`2%水楊酸身體乳210ml二入` 可和 PChome `Nick` 補出的 `水楊酸身體乳雙入組 / 210ml x2` 對齊,進 `exact / total_price / price_alert_exact`;但 `118ml二入組(金蓋限定版)` 對上 PChome 效期品仍保留 `manual_review / identity_review`,不泛用放寬中文入數。
- V10.582 補 PChome 比價通知專業分級與 Nick 副標身份證據NemoTron 價格決策信封現在保留 `momo_price`、`competitor_price`、`candidate_gap_pct` 與 `sales_7d_delta_pct`EventRouter / Telegram 模板會把 `match_type / price_basis / alert_tier` 翻成「直接價格威脅、單位價覆核、身份覆核、壓制告警」與操作邊界PChome crawler 會保留 `Nick` 副標為 `match_name` 給 matcher 使用UI/DB 顯示仍維持原品名,讓容量、入數、濃度資訊可參與比對。
- V10.581 將 V10.580 的重複單品組安全線接進 PChome retryable revalidation 窄門:只允許 `true_low_confidence`、舊診斷為 `match_type=exact / price_basis=manual_review`、無阻擋原因且命中具名安全商品線Bioneo 150ml x2、Cetaphil 150ml x2、Avene 300ml x4、Schick 2+1 入、KOSE 雪肌精 500ml x2 禮盒)的候選進小批次重評;仍由最新版 matcher 最終判斷是否寫入正式 `competitor_prices`。
- V10.580 補 PChome 重複單品組 total-price 窄門:同品牌、同入數、同基礎規格且名稱高度對齊的 150ml x2、300ml x4、2+1 入等候選,可由 `exact / manual_review` 進 `exact / total_price / price_alert_exact`,正式部署前估算 213 筆高分 `true_low_confidence` 中只有 7 筆會轉自動寫入。同步新增 NEW DIRECTIONS 甜杏仁油 vs 杏桃核仁油核心油種 hard veto避免規格一樣但油種不同的錯配污染正式價差Paula's Choice 這類 PChome 端缺 30ml 規格的雙入組仍保留 manual review不放寬全域門檻。
- V10.579 補 PChome 高信心 total-price safe familySAB 私密防護舒緩噴霧 30ml 與 Herbacin 小甘菊 20ml 護手霜在同款式、同規格、無 variant/commercial gap 時可由 focused matcher 進 `exact / total_price / price_alert_exact`讓近門檻重評能真正寫入正式比價Herbacin 柔皙 vs 野生玫瑰等跨 variant 仍保留在 review不放寬全域門檻。同版將 Code Review GCP-B secondary timeout 預設由 60 秒收斂到 25 秒GCP-A preflight 不通且 GCP-B 生成卡住時更快回 deterministic local degraded不呼叫 Gemini/111。
- V10.578 修正 Code Review 靜態掃描 timeout 誤報Hermes deterministic scan 對 `requests.get/post/...` 會檢查同一呼叫 block 的後續行,多行呼叫已帶 `timeout=` 時不再報「HTTP request 未設定 timeout」。避免 V10.577 的 preflight helper 因多行格式被自己誤判為 MEDIUM。
- V10.577 補 Code Review Ollama host preflightOpenClaw 架構評估在 explicit GCP host generate 前先以短 `/api/version` 探測健康度GCP-A 不通時會快速跳 GCP-B不再等 15 秒 generate timeout仍維持 GCP-A/GCP-B 優先、111 預設禁用、Gemini hard-disabled 預設不呼叫。
- V10.576 補 PChome backfill backlog 的型錄 lane counts讓 `/api/ai/pchome-match/backfill/status` 也能回傳 `catalog_variant_review`、`catalog_unit_review`、`catalog_identity_review` 三條操作隊列;同版修正 `OllamaService.generate(allow_111_fallback=False)`,當 lazy resolver 快取到 111 時會強制改試 GCP-A/GCP-B allowlist不再直接 `all 0 hosts failed`,且仍不把長分析推給 111。
- V10.575 拆分 PChome 型錄可比覆核 lane`catalog_comparable` 不再只是一個總數,正式拆成 `catalog_variant_review`(選項/色號/款式待核)、`catalog_unit_review`(入數/檔期/商業條件待核)與 `catalog_identity_review`身份採用待核。Coverage、review queue filter、Dashboard 分段、decision envelope、Webcrumbs host data 都共用同一套 SQL helper 與 metadata仍維持 HITL、不自動寫正式價差讓營運可批次清理最有機會轉成單位價或正式身份的候選。
- V10.574 接上 PChome 型錄/任選可比覆核隊列:沿用 V10.572 的 `catalog_comparable_count` 安全口徑,將高分、無 hard veto、具同品線身份證據但仍有任選/型錄/商業條件待確認的 `true_low_confidence` 候選,拆成獨立 `catalog_comparable` 篩選與 decision envelope。此隊列仍維持 HITL不寫入正式 `competitor_prices`、不算 exact matched並把「型錄可比」與真正「證據不足」分開讓營運可以先批次處理最有機會轉成單位價或正式身份的候選。
- V10.574 新增市場情報 Source Governance → Fetch Target bridge新增 `/api/market_intel/mcp_fetch_target_source_governance_review`、市場情報頁 bridge panel 與 deployment readiness smoke target交叉審核 Professional Source Governance 與 MCP Fetch Target Review要求每個 target `platform_code/source_key` 都能對上已通過治理的公開 source contract仍不抓外站、不讀 robots/sitemap、不開 DB、不寫檔、不執行 CLI、不掛 scheduler。
- V10.572 新增 PChome 決策支援覆蓋率:不放寬 `matched` / `decision_ready` 的 exact identity 門檻,另外把高分、無 hard veto、具同品線與規格證據但因「任選 / 色號 / 型錄 / 即期」仍需覆核的候選,納入 `catalog_comparable_count` 與 `decision_support_rate`。Dashboard、當日業績、成長分析與 backfill 狀態摘要同步顯示「決策支援覆蓋率 / 精準可告警覆蓋 / 型錄可比 / 單位價」,讓覆蓋率提升建立在可解釋情報分層上,而不是把非 exact 商品硬寫成正式同款。
- V10.571 提升 PChome pending 覆蓋率搜尋召回:`PCHOME_FEEDER_MAX_SEARCH_TERMS` 預設由 5 提升到 6新增 `PCHOME_FEEDER_SEARCH_COVERAGE_RESCUE_ENABLED`,在主要搜尋詞與原始名稱 fallback 之間插入狹義 coverage rescue terms。搜尋詞會保留 `5.5g`、`2.4g` 等小數規格,不再變成 `5 5g` / `2 4g`;同時排除外出清潔、卸除髒汙、卸防曬等非身份核心噪音。正式 pilot 顯示 CeraVe / TUNEMAKERS / Embryolisse / Neogence / NIVEA 這類雙語品牌商品常卡在 PChome 搜尋召回,因此補上「英文品牌 + 中文品牌 + 核心身份 + 規格」窄搜尋詞;「品牌 + 品類 + 規格」仍只開給安全品類,避免為了拉 pending 覆蓋率引入假陽性。
- V10.570 補 PChome 身份 / 報價證據契約matcher 的 `match_diagnostic_json` 新增 `identity_evidence`、`offer_evidence`把品牌、品類、identity anchor、型號、規格、入數與 variant guardrail 拆成結構化證據;覆核隊列與 decision envelope 新增 `difference_highlights`,可直接指出容量、入數、色號、香味、款式、補充包、檔期組合等差異。價格明確標記為 offer evidence不再被誤當身份證據Dashboard / PPT / OpenClaw / Webcrumbs 能共用同一份比對證據。
- 外部專業 benchmark 固定節奏:已建立每週一 09:30 自動檢視,並新增 `docs/guides/external_professional_benchmark.md`,把 Google Merchant Center、Google Product structured data、Schema.org Product/Offer/AggregateOffer 與 Baymard 電商 UX 做法轉成可落地準則identity evidence、fresh offer、review 差異高亮、PPT/AI evidence 分層。
- V10.565 補 PChome 覆蓋率操作建議:`/api/ai/pchome-match/backfill/status` 會把低覆蓋率拆成 `operation_backlog`,分別列出刷新舊 identity、重評近門檻、補抓未配對、人工覆核、單位價覆核與過期搜尋救援預覽同時回傳 `recommended_next_action`Dashboard 狀態摘要會顯示「建議執行比價補強 / 刷新過期 identity / 處理覆核」等下一步,讓覆蓋率 KPI 直接連到可執行行動。
- V10.563 收斂正式 preview 假可救候選M.A.C 超持妝輕透濾鏡蜜粉若只有 PChome 端出現明確色號(例如 `#絕絕紫`),會標成 `variant_selection_review` 並維持 `true_low_confidence`,不再佔 recoverable 池SAUGELLA 賽吉兒菁萃潔浴凝露新增潤澤 / 日用型 / 加強 / 黃金女郎型變體互斥,避免同品線不同私密清潔款式被誤救成 matched。
- V10.566 新增市場情報 Professional Source Governance把 robots/REP、sitemap/lastmod、JSON-LD / schema.org structured data、canonical URL、rate limit、公開資料邊界、provenance、snapshot hash 與 idempotency key 變成可審核 source contract。新增 `/api/market_intel/mcp_professional_source_governance` 與市場情報頁卡片、deployment readiness smoke targetAPI/UI 只審核操作員貼回的治理摘要,不抓外站、不讀 robots/sitemap、不開 DB、不寫檔、不掛 scheduler後續 fetch target review 才能引用通過治理的來源。
- V10.561 補 PChome 比價補強前端分段回饋Dashboard 的 PChome 卡片從「補抓產線」改為「比價補強產線」,按鈕與確認文案同步說明會先刷新舊 identity、再重評近門檻與補抓未配對結果區新增刷新 / 重評 / 補抓三段 matched/total 摘要,避免後端已完成分段統計但操作員仍只看到一個籠統成功數。
- V10.560 串起手動 PChome 比價補強三段式流程:`/api/ai/pchome-match/backfill` 現在不只跑近門檻重評與未配對補抓,也會先用小批次 `run_expired_identity_refresh()` 刷新已知 `identity_v2` 舊價格,讓操作員按一次補強就能同時處理「舊 identity 新鮮度」、「near-threshold low_score」與「pending identity」三條主線。結果 payload 新增 `stale_identity_refresh` 分段統計,方便後續 Dashboard / 簡報 / AI 決策知道覆蓋率改善是來自刷新、重評或補抓。
- V10.559 收斂 retryable 有效身份新鮮度:`_fetch_retryable_candidate_skus()` 不再把 `expires_at IS NULL` 的舊 PChome `identity_v2` 當成有效阻擋條件,只有明確 `expires_at > CURRENT_TIMESTAMP` 的新鮮 identity 才會阻止 near-threshold revalidation。未知新鮮度仍走 V10.551 的 expired / recovery 刷新入口,重評後仍必須通過最新版 matcher、hard-veto、auto write safety 與既有正式候選覆寫保護,避免為了拉覆蓋率犧牲準確率。
- V10.558 補 legacy focused identity reason 回刷窄門:舊 attempt 若沒有新版 `focused_exact_total_price_safe` marker但已帶具名 `focused_exact_identity_*` 且該 identity 屬於 matcher total-price safe set並且舊分數已達全域 `MIN_MATCH_SCORE`,可進近門檻重評。這補上歷史資料缺 marker 的漏接情境;仍要求無 hard veto、`exact_identity`、無 commercial / variant / count / bundle 阻擋,最後由最新版 matcher 決定是否能寫正式價差。
- V10.557 收緊 focused reason-based 回刷 guard上一版 reason-based 回刷現在不只要求 `focused_exact_total_price_safe`,還必須同時命中一條具名 `focused_exact_identity_*` 且該 identity 屬於 matcher 的 total-price safe set。這避免未來只有總開關、缺少具名身份證據的舊 attempt 被納入回刷rom&nd / Solone / Summers Eve 等 review-only focused line 仍被測試鎖在自動價差線外。
- V10.556 修 Ollama GCP-B model fallbackGCP-B 若缺 coder/large 指定模型,先用 host-compatible fallback `gemma3:4b` 留在 GCP-B不直接把流量推到 111`model not found` 404 視為模型缺失,不再把整台 GCP-B 標 unhealthy。主機順序仍維持 GCP-A → GCP-B → 111。
- V10.555 補 focused total-price reason-based 回刷:`_fetch_retryable_candidate_skus()` 新增一條結構化 reason 窄門,只要舊 attempt 已帶 `focused_exact_total_price_safe` 且命中 matcher 的 `FOCUSED_IDENTITY_TOTAL_PRICE_REASONS`,即可進近門檻重評;仍要求無 hard veto、`exact_identity`、分數下限,並排除 commercial / variant / count / bundle 等阻擋理由。這讓已經被 matcher 明確判為 total-price exact 的舊候選不再依賴手寫商品名 SQL 才能回刷,同時 rom&nd / Solone / Summers Eve 等 review-only 品線仍不會進自動價差線。
- V10.554 接線香氛 / 精油 focused exact 回刷Herb24 晨霧純精油擴香儀黑色、Pavaruni 40 香味 10ml 精油、Pavaruni 20 香味 450g 香氛蠟燭、Derma 大地有機植萃護膚油 150ml 現在明確標記 `focused_exact_total_price_safe`,並接進 `_fetch_retryable_candidate_skus()` 近門檻舊候選回刷。此入口只收 `low_score / refresh_low_score / true_low_confidence` 中命中精準名稱錨點、無 hard veto、`exact_identity` 且沒有變體 / 商業條件 / 件數衝突的候選Laundrin、好物良品融蠟燈、Yuskin 等仍保留人工覆核,不為了拉覆蓋率強推自動價差。
- V10.553 優化 current PPT/AI 比價結果查詢:`fetch_competitor_comparison_results()` 的 current/latest MOMO 價格改用 `JOIN LATERAL` 取單品最新價,移除 `ROW_NUMBER() OVER (PARTITION BY p.id ...)` window scan歷史報表的 `end_date` cutoff 仍保留在 lateral 子查詢內,維持「指定期間截止日前最新 MOMO 價」語意不變。這能降低簡報、OpenClaw/AI payload 與比價匯出在大量 price_records 下的查詢成本。
- V10.552 收斂決策查詢的新鮮度口徑:`fetch_top_competitor_risks()`、PChome review queue、review sample 與 current PPT/AI 比價結果都不再把 `expires_at IS NULL` 當成有效現價,只接受 `expires_at > CURRENT_TIMESTAMP` 的 PChome identity_v2 價格。未知新鮮度只留在 coverage 的診斷欄位與 V10.551 刷新入口不再進入價格風險、簡報、AI 決策或覆核排除條件。
- V10.551 收斂未知新鮮度刷新與補抓排序:`_fetch_expired_identity_skus()` / `_fetch_expired_identity_recovery_skus()` 將 `expires_at IS NULL` 視為必須刷新或可搜尋救援的未知新鮮度 identity和 V10.549「未知新鮮度不算可決策覆蓋率」口徑對齊;兩條路徑改用 `JOIN LATERAL` 取最新 MOMO 價,移除 product-wide window scan。`_fetch_unmatched_priority_skus()` 也改用 lateral 最新價,並優先重搜低風險 `no_result / refresh_no_result`,讓 V10.550 的安全召回詞先用在最可能被救回的商品。
- V10.550 補安全搜尋召回詞:`_build_variant_recall_search_plan()` 對低風險穩定品類新增 `品牌 + 品類` 的補搜尋詞,讓 `no_result / refresh_no_result` 更有機會找到 PChome 候選後再交給 matcher 安全判斷;美甲片、指甲油、唇彩、香氛/精油、粉底、防曬、任選/色號/款式等高 variant 風險商品不走通用召回DASHING DIVA 仍只走既有 line-specific recall + sort fallback。此變更不改 `MIN_MATCH_SCORE`、hard veto、fresh-search write safety 或 stronger existing match 覆寫保護。
- V10.549 收斂比價新鮮度 KPI 口徑coverage cache 升到 v10`expires_at IS NULL` 不再算進「可用比價 / decision ready」改拆成 `unknown_freshness_matches` / `unknown_freshness_count`避免沒有到期時間的舊資料被當成可直接決策的新鮮價格。Dashboard / daily / growth 同步顯示未知新鮮度與「未形成有效身份配對」,並把 PChome/MOMO 價格方向文案改成 `PChome 價格壓力` / `MOMO 價格優勢`,降低誤讀。
- V10.548 接線更多 focused exact 舊候選回刷:把 matcher 已驗證可安全走 total-price 的 3W CLINIC 膠原蛋白粉底液 50ml x2、花美水 Moisture/Inclear 1.7g x3、KUSSEN 寶寶益菌屁屁膏 50ml 3 入、Lab52 齒妍堂嬰幼兒/汪汪隊牙刷 2 入接進 `_fetch_retryable_candidate_skus()` focused true-low / rescore 窄門。這只擴大「舊候選可被新版 matcher 重評」的入口,不改 `MIN_MATCH_SCORE`、hard veto、auto price write safety 或既有覆寫保護。
- V10.547 強化單位價覆核洞察:`manual_unit_price_required` 不再只是人工狀態覆核隊列與商品看板會重新帶出單位價換算、MOMO/PChome 單位價方向、差距百分比與處理建議;決策信封 / OpenClaw / PPT 摘要可讀到 `unit_price_insight`。人工覆核寫回也會保留原始 `match_diagnostic_json` / comparison mode / diagnostic codes避免後續簡報、審計或 AI 策略只剩人工文案而失去 matcher 證據鏈。
- V10.546 補近門檻舊候選回刷隊列:`run_retryable_candidate_revalidation()` 新增 `legacy_unmasked_attempt`,當最新狀態是 `no_result` / `refresh_no_result` / `expired_match` 時,可回撈同 SKU 早期近門檻候選交給最新版 matcher 重評;仍要求 candidate id、分數下限、無 hard veto、exact_identity且不打開人工否決、單位價、identity_veto 或 protected existing match。
- V10.545 收斂 Dashboard 比價覆蓋率口徑coverage cache 升到 v9新增身份覆蓋、可用比價、新鮮度、待補身份、過期身份與人工閉環欄位商品看板和 PChome 覆核頁改只把真正待處理狀態算進「比價覆核」,人工已否決 / 人工單位價 / 需補研究改列為人工閉環PChome competitor map 只吃有效價格、新鮮、identity_v2 最新 row資料新鮮度也改看可用比價 row。
- V10.544 收斂變體安全與 YES 指甲工具線:新增 YES 德悅氏指甲剪附除垢銼刀、腳皮銼腳板、藍寶石銼刀、三面拋光棒與 6/8cm 指甲剪的精準 total-price 線,要求同品牌、同工具名稱、同尺寸與同亮面/霧面/可收納/三面/不掉屑等款式訊號;同步接進 revalidation SQL。新增 MUJI / COCODOR 未知香味差異與 OPI 無型號不同色名 hard vetoHOOOME 暖燈材質差留人工覆核,搜尋詞也會優先帶香味/色名,提升 crawler 精準候選率。
- V10.543 打通 `rescore_accepted_current` 窄門回刷:已進人工覆核池的候選若命中具名 focused exact 線,可進 `run_retryable_candidate_revalidation()` 重新評分;新增 SK-II 青春露 330ml 兩入、AMIINO 安美諾 30ml、YES 腳指甲剪刀 10.5cm、YES 極細指甲緣硬皮剪刀 9cm 的安全 total-price 線,並補 ANNY / OPI 指甲油型號 code hard veto避免不同色號被錯配。
- V10.542 拆開「可用比價覆蓋率」與「身份覆蓋率」:`decision_ready_rate = fresh identity / ACTIVE 商品數`Dashboard 第一張 KPI 改顯示真正可進入決策、圖表、簡報的比價資料比例daily / growth / Webcrumbs / OpenClaw payload 同步輸出,避免把身份覆蓋、新鮮率、價格可用率混成單一數字。
- V10.541 補正式覆核頁高信心 exact 線The Ordinary 咖啡因 EGCG 單側漏 30ml、Natures Care 綿羊油同入數 125ml/125m、TOMOON 指甲剪同 L/S 尺寸、HH 私密潔淨露+衣物手洗精雙 200ml、SEBAMED 護潔露 200ml x2、YES 德悅氏 9cm 剪刀;都同步進 revalidation SQL且 TOMOON/O.P.I 不同型號或尺寸仍不得自動通過。
- V10.540 補 O.P.I 類光繚指彩精準型號線:雙方同為 O.P.I 類光繚 / 如膠似漆指甲油或指彩,且共享 `ISL...` 型號 token 時才允許 total-price不同型號/色號仍不得自動寫入。同步把此族群接進 `true_low_confidence` revalidation 窄門,降低高信心指彩候選卡在人工覆核池的比例。
- V10.539 補 PChome 任選 catalog focused exact 線FLORTTE 水果沙拉眼線液筆 0.5ml、露得清護手霜 56g 無香/有香、Kanebo ALLIE 持采亮化 UV 防曬水凝乳 60g 雙方皆任選時可走 total-price同步接進 revalidation queue。focused bypass 新增 commercial condition 防線,`即期品` 等商業狀態差異不會被自動寫入正式價差。
- V10.538 修 ai_calls provider CHECK 對齊Hermes/Ollama 全失敗或未選定 host 時的 `ollama_other` 只作 telemetry bucketmigration 043 放行此值,`ai_call_logger` 也會將空值/unknown/非白名單 provider 正規化,避免觀測寫入失敗。
- V10.537 將 V10.536 focused exact 線接進 `run_retryable_candidate_revalidation()` 窄門:既有 `true_low_confidence` 舊候選若命中新品線且無 hard veto / 型別、款式、香味、件數、組合阻擋,就可重新走 matcher 寫入正式價差;有色號/香味/即期等阻擋仍不進回刷。
- V10.536 補 PChome 高分 `true_low_confidence` 安全救回線:新增花美水 Relax 薰衣草潤滑凝膠 1.7g x3、St.Clare 私密呼呼慕斯 x2 / 慕斯+噴霧組、BIOPEUTIC 果酸煥膚水凝乳 20% 150ml、台塑生醫嬰兒沐浴洗髮 3 件組、Elizabeth Arden 八小時護唇膏 SPF15 3.7g x3、理膚寶水全面修復潤唇膏 7.5ml focused total-price 規則;這些都要求同品牌、同品線與同規格/同組合,仍保留色號、香味、款式敏感品的 `variant_selection_review` 防線。
- V10.535 修 ElephantAlpha 價格 trigger statement timeout`price_drop_alert` / `market_opportunity` / DB evidence prefetch 改為先篩最近有效 PChome identity_v2再用 `JOIN LATERAL` 查單一 SKU 最新 MOMO 價格;保留 match_score/tags/diagnostic evidence避免 scheduler 週期性重查整張 `price_records`。
- V10.534 收緊 PChome rescore accepted gate`no_match / price_basis=none / alert_tier=suppress` 不得再進 `rescore_accepted_current`,並新增 `--retract-unsafe-accepted` 退回舊的 unsafe accepted rowsDashboard / daily / growth / OpenClaw 文案改為「重算待人工覆核」,避免操作員把人工覆核隊列誤解為可直接採用或可自動寫價。
- V10.533 補 ElephantAlpha legacy OpenClaw advisory 相容:`generate_dynamic_pricing_strategy` 與既有 `generate_market_strategy` / `generate_resource_optimization_strategy` 一樣只記錄為 skipped不再觸發 `Unrecognized step` 與 circuit breaker避免舊協調器輸出的建議型動態定價步驟被誤解為真正可執行任務。
- V10.532 修正 PChome coverage / review queue 口徑落差:`fetch_competitor_coverage()` 的 `attempt_status` / `rescore_accepted_count` / `actionable_review_count` 改跟 review queue 一樣統計「沒有新鮮有效 identity」的商品而不是只看「完全沒有 identity」這讓已過期 identity 的 `rescore_accepted_current` 待審能正確顯示在 Dashboard / 狀態 API。
- V10.531 補 PChome matcher 過度保守的安全 exact 線:同品線、同規格、同數量的多件組若沒有 variant / count / bundle / commercial / unit-price 等阻擋理由,且商品型別完全對齊,允許進 `exact / total_price / price_alert_exact`;新增 DHC 純欖護唇膏 1.5g、FRUDIA 蜂蜜藍莓護唇膏 10g、SEBAMED 嬰兒護唇膏 4.8g x2、理膚寶水滋養修護潤唇膏 4.7ml 的 focused total-price 規則。負例仍鎖住混合組、香味款、粉底色號與蠟燭 catalog不放寬全域門檻。
- V10.530 輕量化 PChome 狀態 preview 並暫停 `recover-stale` 主操作入口:`_fetch_retryable_candidate_skus()` 先從最新 `competitor_match_attempts` 縮小可重評候選,再用 `JOIN LATERAL` 只取該 SKU 最新 MOMO 價,避免 `/api/ai/pchome-match/backfill/status` 因 `price_records` 全量 window scan 超時;正式 smoke 同時顯示過期 identity fresh-search rescue 5 筆耗時約 109 秒且 0 筆成功,因此 Dashboard 移除「救援過期 40 筆」按鈕,只保留 `stale_recovery_preview` 的只讀「可救援」觀測;後端 `/api/ai/pchome-match/recover-stale` 改由 `PCHOME_STALE_RECOVERY_ENABLED=true` 顯式開關才可執行,避免操作員誤按低成功率慢路徑拖住 worker。
- V10.529 補強 `recover-stale` 名稱風險擋詞:過期 identity 搜尋救援會先排除 `+`、`x2`、`*2` 等組合暗示,以及湛藍、麋香、海洋、玫瑰、薰衣草、生理呵護、日用型、清爽、潤澤等常見變體 / 香味 / 版本詞,避免同品牌同規格但不同香味、不同膚感、不同使用情境的 stale pair 進慢速 fresh search。
- V10.528 將 `recover-stale` 救援 preview 改成輕量雙階段篩選SQL 從過期 `competitor_prices` 小集合出發,只做 identity_v2、過期、exact/total_price/price_alert_exact 等必要條件並限制候選量,再用 `JOIN LATERAL` 取 ACTIVE 商品最新 MOMO 價variant / catalog / commercial condition / 高風險名稱訊號改在 Python 對小樣本過濾,避免正式站看板狀態端點因全量 price_records、JSONB + regex 過重查詢拖垮 app worker。
- V10.527 收斂 PChome 過期 identity 搜尋救援隊列:`recover-stale` 不再直接吃全部過期 `identity_v2`,改走 `_fetch_expired_identity_recovery_skus()`,只收既有正式診斷為 `exact_identity / total_price / price_alert_exact` 且無 variant、catalog、commercial condition、count、bundle、unit-price 等阻擋理由的舊配對;名稱含任選、多款、香味、色號、即期、融燭燈、香氛蠟燭等高風險訊號也先排除,避免慢速 fresh search 把人工覆核型 stale pair 全部掃進來。
- V10.526 將 PChome 近門檻重評池與過期 identity 搜尋救援變成可觀測、可操作產線:`preview_retryable_candidate_revalidation()` / `preview_expired_identity_recovery()` 都是 read-only不啟動 PChome 搜尋、不呼叫 LLM、不寫 DB`/api/ai/pchome-match/backfill/status` 回傳 `revalidation_preview` / `stale_recovery_preview`Dashboard 顯示「可重評 / 窄門 / 可救援」數字,並新增「救援過期 40 筆」按鈕呼叫 `/api/ai/pchome-match/recover-stale`,只在舊 PChome ID 缺失或低分時走受控 fresh-search recovery最後仍經 hard veto、auto price write safety 與 overwrite protection。
- V10.525 補高分 review-gated exact 舊候選重評入口:`run_retryable_candidate_revalidation()` 仍以 `low_score / refresh_low_score / recoverable_low_score` 為主,只額外允許 Beauty Foot / KAMERIA / TS6 / Vaseline 這批已補 focused exact 規則、舊分數 >= 0.95、無商業狀態 / 款式 / 入數 / 組合阻擋理由的 `true_low_confidence` 進窄門重評,讓 V10.523 的安全規則可以實際回收舊資料,不把所有人工審核候選打開。
- V10.524 將「待刷新」變成可操作入口:商品看板 PChome 補抓產線新增「刷新過期 120 筆」按鈕,呼叫 `/api/ai/pchome-match/refresh-stale` 背景執行 `run_expired_identity_refresh()`,只刷新既有 `identity_v2` 的 PChome product_id不跑 fresh search recovery、不呼叫 LLM完成後重算 AI 挑品並清除 Dashboard / 競價快取。
- V10.523 補一批高分真同款 exact identity 比價規則Beauty Foot 足膜、KAMERIA 積雪草足膜、TS6 蜜愛潤滑液 / 蜜桃煥白凝膠 / 極淨白+煥白組合、Vaseline 嬰兒高純修護凝膠在規格、入數、品牌與品線完全對齊時可進 `exact / total_price / price_alert_exact`,讓可用比價覆蓋增加;同時保留 TS6 香味衣物手洗精等 variant-sensitive 款式在 `manual_review`,不放寬全域門檻。
- V10.522 將 PChome 補抓狀態 API 接上 read-only coverage snapshot`/api/ai/pchome-match/backfill/status` 會同步回傳身份覆蓋、新鮮率、待刷新與待補抓數Dashboard 補抓產線即使沒有最近任務結果,也能直接判讀下一步該刷新過期價格或補抓未搜尋商品。
- V10.521 將比價新鮮度 stale 指標上屏:首頁 KPI / PChome 補抓產線 / daily / growth 都顯示價格過期數,讓操作員分清「已確認同款但價格待刷新」與「尚未找到身份配對」;過期 identity refresh 也優先刷新 `total_price / price_alert_exact` 的正式價差配對。
- V10.520 拆開過期價格刷新與搜尋救援:`run_expired_identity_refresh()` 只刷新既有 `identity_v2` PChome product_id不再因少數 product_id 查不到或低分而同步進入慢速 `fresh_search_recovery`;缺失 / 低分候選交給 `run_retryable_candidate_revalidation()` 處理,避免正式刷新 500+ 筆時被外部搜尋拖死,讓價格新鮮度可以穩定批次回升。
- V10.519 對齊 Webcrumbs host data metadata 與新版比價覆蓋口徑:`services/webcrumbs_host_data_service.py` 會同時輸出身份覆蓋、價格新鮮、過期配對與待補抓數,讓 shared-ui plugin / 其他專案 proxy 不會把 `coverage_rate` 誤讀成價格可用率。
- V10.518 修正 PChome 比價覆蓋率口徑與新鮮度產線:`fetch_competitor_coverage()` 改拆「身份覆蓋」與「價格新鮮」,覆蓋率不再因 `expires_at` 過期被歸零;首頁 / 業績 / 成長頁同步顯示身份覆蓋、價格新鮮數與新鮮率。PChome 快取 TTL 預設由 6h 改 48h並把每日 expired identity refresh / retryable / unmatched limits 改為環境變數,預設提高到 1200 / 240 / 240避免 1800+ 已配對 identity 因刷新量不足長期失效。
- V10.517 補 PChome 近門檻比對安全 exact 與香氛 variant 防線Lab52 齒妍堂汪汪隊嬰幼兒牙刷 2 入組可由低分區提升為 `exact / total_price / price_alert_exact`Les nez 香氛融蠟燈不同款式、Time Leisure 香薰蠟燭單側香味款式會被留在覆核 / veto不再進 recoverable 自動回刷,避免為了壓低 low_score 而錯配款式。
- V10.515 補 Webcrumbs host data 硬性授權:即使正式環境 `DISABLE_LOGIN=true` 讓一般 `@login_required` 放行,`/api/webcrumbs/marketplace-host-data` 仍必須有登入 session 或 `X-Internal-Key` 才能取真實 SKU/價差;`/webcrumbs` 未授權時只注入 `auth_required` 空狀態,避免 inline seed data 公開正式比價資料。
- V10.514 新增 Webcrumbs MOMO/PChome host data read-only API`/api/webcrumbs/marketplace-host-data` 回傳與 `/webcrumbs` inline seed 相同的登入後 JSON contract提供 plugin / QA / 其他專案 proxy 驗證API boundary 明確標示不寫 DB、不呼叫 LLM、不抓外站只允許 exact / total_price / price_alert_exact 價差摘要。
- V10.513 外部工具診斷頁 payload 模組化:新增 `services/external_tool_payload_service.py`,把 Metabase/Grist/Webcrumbs 的診斷 payload 與 Webcrumbs host data 組裝移出 `routes/system_public_routes.py`,讓 route 回到 HTTP glue`system_public_routes.py` 從 600+ 行降至 500 行內。
- V10.512 Webcrumbs live plugin 接上 MOMO/PChome 只讀 host data新增 `services/webcrumbs_host_data_service.py`,復用 `competitor_intel_repository.fetch_top_competitor_risks()` / coverage把 exact / total_price / price_alert_exact 價差摘要轉成 `StockPlatformSharedUI.marketSnapshot` / `aiCandidate`;不呼叫 LLM、不抓外站、不寫 DB無風險或失敗時仍輸出安全空狀態。
- V10.511 Webcrumbs live plugin 補 host data 安全空狀態:`/webcrumbs` 會注入 `StockPlatformSharedUI.marketSnapshot` / `aiCandidate` 的診斷空資料,避免 plugin fallback demo 數字被誤認成真實市場或 AI 建議。
- V10.510 Webcrumbs 從 runtime 接線推進到專案內 live plugin 試點:`/webcrumbs` 會設定 `StockPlatformSharedUI.allowedPluginUris` 並嵌入同源 `/webcrumbs-assets/plugins/finance.market-ticker-strip/0.1.0`、`finance.ai-candidate-card/0.1.0`,用同一頁同時驗 runtime、plugin proxy 與共享 UI loader 初始化。
- V10.509 新增市場情報 MCP Fetch Candidate Queue Writer Review Decision Approval Writer Preflight 安全預覽 gate只審核 human approval 通過後由操作員貼回的 writer preflight 摘要,確認 approval identity、writer_preflight_id、row count、dedupe keys、approved decision 到 target review_state 的逐列映射、decision/approval/preflight evidence refs、exact identity / variant / overwrite guard 與 operator boundaryAPI 不讀 token、不執行 CLI、不開 DB、不寫 preflight/approval/decision/match、不更新 review_state、不補 queue、不掛 scheduler只放行到後續 CLI review / run package 設計。
- V10.508 Webcrumbs 轉為 momo-pro 同源 asset proxy`WEBCRUMBS_RUNTIME_URL` 預設改為 `/webcrumbs-assets/loader/webcrumbs-compatible-loader.js`,新增 allowlist proxy 只代理 188 Shared UI Hub 的 `loader/`、`plugins/`、`demo/`,避免 `webcrumbs.wooo.work` 公網 TLS / Basic Auth 尚未收斂時影響正式頁面載入;`/webcrumbs` 診斷頁同步顯示 asset upstream。
- V10.507 接入 Webcrumbs 共用 UI Runtime新增 `WEBCRUMBS_*` 環境設定與 `/webcrumbs` 診斷入口,`ewoooc_base.html` 會在 runtime 啟用且 URL 有效時載入自架 Webcrumbs script側欄新增 Webcrumbs 入口,並補 `docs/guides/webcrumbs_shared_runtime.md` 作為跨專案接入手冊。生產仍需固定版本與自架 plugin URI不使用官方 `@latest`。
- V10.506 新增市場情報 MCP Fetch Candidate Queue Writer Review Decision Approval 安全預覽 gate只審核 review decision 通過後由操作員貼回的人工 approval 摘要,確認 approval identity、row count、dedupe keys、approved decision、evidence refs、exact identity / variant / overwrite guard 與 operator boundaryAPI 不讀 token、不執行 CLI、不開 DB、不寫 approval/decision/match、不更新 review_state、不補 queue、不掛 scheduler只放行到後續人工 approval writer preflight 設計。
- V10.505 新增市場情報 MCP Fetch Candidate Queue Writer Review Decision 安全預覽 gate只審核 review inventory 通過後由操作員貼回的人工 candidate queue review decision 摘要,確認 decision identity、target table、row count、dedupe keys、`needs_review` 現態、允許決策集合、evidence refs、matched row exact-identity/variant/overwrite guard、operator confirmation 與 forbidden API actionsAPI 不讀 token、不執行 CLI、不開 DB、不寫 decision record、不更新 review_state、不寫 match result、不補 queue、不掛 scheduler。UI 同步新增 Decision gates / Inventory link / Decision summary / Decision rows / Boundary next 預覽區。
- V10.504 新增市場情報 MCP Fetch Candidate Queue Writer Review Inventory 安全預覽 gate只審核 writer review handoff 通過後由操作員貼回的 read-only candidate queue inventory 摘要,確認 handoff identity、target table、row count、dedupe keys、review_state、artifact paths、read-only query result、missing/duplicate rows、operator confirmation 與 forbidden API actionsAPI 不讀 token、不執行 CLI、不開 DB、不寫 queue、不更新 review_state、不做 inventory query、不掛 scheduler。主 gate 拆為 inventory / gates / sample 三檔,避免單檔膨脹。
- V10.503 新增市場情報 MCP Fetch Candidate Queue Writer Review Handoff 安全預覽 gate只審核 post-closeout inventory review 通過後的人工 candidate queue review 交接包,確認 inventory linkage、handoff identity、target table、row count、artifact paths、review contract、forbidden API actions 與 operator confirmationAPI 不讀 token、不執行 CLI、不開 DB、不寫 queue、不更新 review_state、不掛 scheduler。
- V10.502 修正 AiderHeal 自動修復診斷鏈:先做 ADR-020 檔案白名單再打 110 preflight`tests/` finding 會明確略過而不誤報 repo preflightCode Review 完成通知會把全數不在白名單的 finding 標成需人工處理,不再宣稱已觸發 AiderHeal白名單放行 `services/routes/database` 子目錄 Python 檔preflight 通知帶 stderr/stdout 細節,健康檢查同時接受 `/health` 回 `ok` 與 `healthy`。
- V10.501 新增市場情報 MCP Fetch Candidate Queue Writer Post-Closeout Inventory Review 安全預覽 gate只審核 closeout review 後由操作員 shell 完成的 live inventory read-only 摘要,確認 closeout linkage、row count、inventory artifact、closeout review artifact、read-only query result、missing/duplicate rows 與 operator confirmationAPI 不讀 token、不執行 CLI、不開 DB、不寫 queue、不做 inventory query、不掛 scheduler。
- V10.500 新增市場情報 MCP Fetch Candidate Queue Writer Run Closeout Review 安全預覽 gate只審核 receipt review 通過後的 operator closeout 摘要,確認 receipt linkage、closeout artifact、receipt review artifact、post-closeout inventory plan、writer output / post-write smoke / backup manifest、rollback note 與 operator confirmationAPI 不讀 receipt 原文、不讀 token、不執行 CLI、不開 DB、不寫 queue、不做 post-closeout query、不掛 scheduler。
- V10.499 新增市場情報 MCP Fetch Candidate Queue Writer Run Receipt Review 安全預覽 gate只審核操作員 shell writer run 後貼回的 receipt 摘要,確認 readiness linkage、run package id、候選/dedupe keys、writer output、post-write smoke、backup path 與 operator confirmationAPI 不讀 receipt 原文、不讀 token、不執行 CLI、不開 DB、不寫 queue、不做 post-write query、不掛 scheduler。
- V10.498 新增市場情報 MCP Fetch Candidate Queue Writer Run Readiness 安全預覽 gate只審核 run package review 後的操作員 readiness 證據,確認 run readiness artifact、reviewed sample、備份、read-only preflight 與 post-write smoke 路徑安全,以及 CLI-only / approval token shell-only 邊界API 不產檔、不讀 token、不執行 CLI、不開 DB、不寫 queue、不掛 scheduler。
- V10.497 新增市場情報 MCP Fetch Candidate Queue Writer Run Package Review 安全預覽 gate只審核 CLI review 通過後的 operator run package 草案,要求 package id、artifact manifest、operator shell command sequence、candidate/dedupe keys 與 CLI review 對齊API 不產檔、不讀 approval token、不執行 CLI、不開 DB、不寫 queue、不掛 scheduler只放行到 run readiness review。
- V10.496 新增市場情報 MCP Fetch Candidate Queue Writer CLI Review 安全預覽 gate只審核 writer preflight 後的 CLI review 草案,確認 script path、target table、preflight id、payload row count、candidate/dedupe keys 與 command argv禁止 API 執行 CLI、禁止 `--execute` / `--apply-real-write` / `--approval-token` 進 payloadAPI 不讀 token、不寫檔、不開 DB、不寫 queue、不掛 scheduler。
- V10.495 新增市場情報 MCP Fetch Candidate Queue Writer Preflight 安全預覽 gate只審核 queue review 後的 writer preflight 草案,確認 target_table、write_mode、dedupe strategy、insert columns、payload rows 與候選 key 對齊API 不開 DB、不執行 CLI、不建立 queue、不更新 review_state、不寫 DB、不連外、不掛 scheduler。
- V10.494 新增市場情報 MCP Fetch Candidate Queue Review 安全預覽 gate只審核 candidate handoff 後的人工 queue review 草案,要求候選 key 對齊、review_state 停在 needs_review、allowed actions 限定人工確認/否決/延後、queue_write_status 維持 not_persistedAPI 不建立 queue、不更新 review_state、不寫 DB、不連外、不掛 scheduler。
- V10.493 新增市場情報 MCP Fetch Candidate Handoff Review 安全預覽 gate只審核 parser review 後的候選交接包,確認 source/candidate key 對齊、queue policy 仍是 manual preview、候選數維持小批次、無 raw/secret/side-effectAPI 不建立 queue、不寫 DB、不讀 artifact、不連外、不掛 scheduler。
- V10.492 收緊 PChome 近門檻自動回刷隊列:`retryable_candidate_revalidation` 不再把 `identity_veto`、`unit_comparable`、`true_low_confidence` 納入每日自動回刷;只處理 `recoverable_low_score` 與 legacy `low_score / refresh_low_score`,並要求無 hard veto、仍在 `exact_identity`、且具備同品線/identity anchor 證據。這讓「可救回」與「正確阻擋」在操作層面真正分流,避免為了壓低 low_score 而重跑不該自動推進的候選。
- V10.491 新增市場情報 MCP Fetch Result Parser Review 安全預覽 gate只審核操作員貼回的 parser 結構化摘要,對齊 receipt source/path、候選必要欄位、公開 URL、小批次上限與 raw HTML/secret/side-effect 風險API 不讀 artifact、不執行 parser CLI、不抓外站、不寫 DB、不掛 scheduler。
- V10.489 補 PChome 低分同款人工覆核回收與 gate-pass 風險邊界TS6 超美白香氛誘霜 120g/ml、W 修護保養蝸牛特潤修護面膜 6 片、Derma 大地 Eco 植萃護膚油 2 入,從低信心升成 `identity_review` 人工覆核候選Clarins 輕盈美體護理油 vs 身體調和護理油、台塑生醫嬰兒沐浴/洗髮組合數量反轉、isLeaf 私密慕絲香型數量不一致改 hard vetoHOOOME 大理石暖燈 vs 泛稱經典款改留 `variant_selection_review`。正式價差表仍需人工採用才會寫入。Production 已部署 `/health=V10.489`500 筆 read-only audit 由 V10.486 基線 `gate_pass=129 / identity_veto=1 / still_low=370` 收斂為 `gate_pass=124 / identity_veto=4 / still_low=372`。測試:完整 `pytest` 1289 passed / 9 skipped。
- V10.488 新增市場情報 MCP Fetch Run Receipt 安全預覽 gate只審核操作員 dry-run receipt不執行 CLI、不抓外站、不寫 DB。
- V10.486 補 PChome near-threshold 風險邊界NEW DIRECTIONS 甜杏仁油 vs 酪梨油直接 `core_ingredient_line_conflict` hard vetoCOCODOR 經典擴香瓶多款任選 vs generic、KAMERIA 足膜任選三款 vs 單一涼感足膜、Hakugen 白元入浴劑橘盒/綠盒不同變體都保留 `variant_selection_review`,不進可採用 gate。Production 已部署 `/health=V10.486`240 筆 near-threshold audit `gate_pass 83→79`、`identity_veto 0→1`、`still_low 157→160`。測試:`tests/test_marketplace_product_matcher.py`、`tests/test_competitor_match_attempts_persistence.py`、`tests/test_competitor_match_attempt_rescore_audit.py` 通過。
- V10.485 補 NITORI 香氛噴霧器短型號防線read-only near-threshold pilot 找到唯一 gate pass 為 5510 vs J82 LBR不應入隊matcher 現在會把 `J82` 這類短英數型號納入 NITORI diffuser model conflict與 5510 / YX168 等不同型號一樣 hard veto。Production 已部署 `/health=V10.485`120 筆 near-threshold audit 由 `gate_pass=1` 變 `gate_pass=0`accepted audit `scanned=89 / gate_pass=89 / still_low=0`。測試:`tests/test_marketplace_product_matcher.py`、`tests/test_competitor_match_attempts_persistence.py`、`tests/test_competitor_match_attempt_rescore_audit.py` 通過。
- V10.484 拆分 PChome manual gatePOWERMAN 男性私密養護液 30ml、PHYSIOGEL AI 冰鎮精華露 200ml 2入、TS6 緊彈水嫩凝膠 40g、DERMA 寶寶洗髮沐浴露 150/500ml、Clarins 黃金亮眼萃 20ml、Cetaphil 長效潤膚乳 237/473ml 等明確同款可走 `exact / total_price / price_alert_exact`COCODOR 大豆蠟燭單側多款任選改留 `variant_selection_review`Pavaruni 雙側 20 香味蠟燭不受新型錄保護誤傷。Production 曾部署 `/health=V10.484`,並退回 COCODOR 舊 accepted 風險 1 筆。測試:`tests/test_marketplace_product_matcher.py`、`tests/test_competitor_match_attempts_persistence.py`、`tests/test_competitor_match_attempt_rescore_audit.py` 通過。
- V10.483 收斂舊 gate pass 風險NARS 遮瑕蜜任選、LOREAL 玻尿酸啵啵精華水/液態紫熨斗 vs 水光精華、SEBAMED 洗髮乳任選、Schick 舒綺 2-in-1 型號落差、TAICEND 保護膜 vs 噴霧,現在都會保留高分但加 `variant_selection_review` 與專屬 reason不再被 rescore 自動送進 accepted queue。Production 已部署 `/health=V10.483`;目標 5 SKU audit `gate_pass=0 / still_low=5`,並用 `--retract-variant-accepted` 退回 4 筆舊 accepted 變體風險latest accepted audit `scanned=90 / gate_pass=90 / still_low=0`。測試:`tests/test_marketplace_product_matcher.py`、`tests/test_competitor_match_attempts_persistence.py`、`tests/test_competitor_match_attempt_rescore_audit.py` 通過。
- V10.482 補 exact variant-safe 回收LUSH 櫻之花身體噴霧 200ml、ARTMIS 金縷梅/蔓越莓私密清潔慕斯 250ml、SO NATURAL FIXX 120ml plain 與 Baan 原味/草莓同 catalog若雙方同品名、同規格且同明確 variant移除過度保守的 `variant_selection_review` 並進 `exact / total_price / price_alert_exact`SO NATURAL 經典款/光澤款/霧面款/夏日款 catalog 對單款 120ml 仍維持人工覆核。Production 已部署 `/health=V10.482`,並只 materialize 5 筆新增 exact-line SKU 到 `rescore_accepted_current`,最新 accepted audit `scanned=94 / gate_pass=94 / still_low=0`。測試:`tests/test_marketplace_product_matcher.py`、`tests/test_competitor_match_attempts_persistence.py`、`tests/test_competitor_match_attempt_rescore_audit.py` 通過。
- V10.481 補 rescore accepted retraction 工具缺口:`--retract-variant-accepted` 不只看舊 row 已存的 `diagnostic_codes`,也會用當前 matcher 重判 latest `rescore_accepted_current`;若新版規則已變成 `variant_selection_review / low_score_current`,會追加退回 `true_low_confidence`,避免舊 accepted queue 殘留不該採用候選。Production 已先保守 materialize 15 筆安全 SKU再退回 7 筆舊 accepted 變體風險;最終 `rescore_accepted_current=89`accepted audit `gate_pass=89 / still_low=0`。
- V10.480 依 production accepted-current 風險樣本補安全閘門rom&nd 零絲絨/果凍唇釉不可被果汁唇釉多款 listing 誤收為同款Relove 潔淨凝露若一側為傳明酸/淨白活性變體改送 `variant_selection_review`1990 融燭燈不同設計(歐式可彎 vs 韓風原木底座)改 hard veto。此版先清 accepted queue 風險,再做保守 materialize。
- V10.479 依 production audit 再補二階風險Cetaphil 修護乳 vs 潔膚露改 hard veto私密防護慕絲二款可選 vs 單一香型、雪芙蘭滋養霜 vs 單側清爽型改走 `variant_selection_review`,避免仍殘留在 accepted queue。
- V10.478 補 PChome 高分錯配 / catalog 變體防線:精油/香氛類若兩側明確香味不同(如檸檬草 vs 茶樹)直接 vetoNOW 椰子油膏 vs 乳木果油、港香蘭漢本 vs 艾魔菈爽身粉改為商品線硬擋;多色/多香/數字區間 catalog 對單一款式(粉餅盒、眉筆、眼線膠筆、車用擴香蕊等)只進 `variant_selection_review`,不自動進 accepted queue。
- V10.477 補 PChome 高分錯配防線SPF 數值不同(如 SPF25 vs SPF50直接 vetoMAKE UP FOR EVER 定妝噴霧 vs 活氧水不同線直接 veto多款任選對單一款私密潔浴露、身體去角質、乳液、染眉膏等與單側色號改送 `variant_selection_review`,避免高分候選誤入 accepted queue。
- V10.476 補 PChome 商品比對「商業條件差」防線:即期品、效期/保存期限、盒損、福利品等條件若只出現在單側matcher 會加 `commercial_condition_gap` + `variant_selection_review`,保留高分但不讓 rescore 自動進 accepted queue。這可避免 3W CLINIC 粉底液、KAMERIA 足膜、Sisley 全能乳液這類同名但商品狀態不同的候選被當成一般正品價差。
- V10.475 補 PChome rescore 操作與高分錯配防線:`scripts/audit_competitor_match_attempt_rescore.py` 預設不再只掃 `strong_exact_spec_match`,避免漏掉 `focused_exact_*` 等新版 matcher 理由matcher 新增暖燈 S/M/L 尺寸差、NITORI 香氛噴霧器型號差的 hard veto並把彩妝色號單邊出現的高分候選送進 `variant_selection_review`,避免 LA MER 氣墊等色號型商品被誤入 accepted queue。測試`tests/test_marketplace_product_matcher.py`、`tests/test_competitor_match_attempts_persistence.py`、`tests/test_competitor_match_attempt_rescore_audit.py` 通過。
- V10.474 補 PChome near-threshold matcher / feeder 下一階段:新增 HOOOME 白色經典香氛暖燈與 Gdesign Aroma Lava 2.0 的窄範圍 total-price exact 回收Recipe Box 可撕式水性兒童指甲油只進 identity_review不自動寫正式價差Pavaruni 蠟燭 vs 精油、DASHING DIVA 不同款式仍維持 veto/低信心。known-id refresh 現在會對 hard-veto 舊候選執行 fresh search recoverymissing known-id 若 fresh search 只找到低分候選也會保留 best candidate + diagnostics而非落成 `refresh_no_result`;正式覆寫保護新增 stronger existing guard避免較弱新候選以高分覆蓋既有強正式配對。測試`tests/test_marketplace_product_matcher.py`、`tests/test_competitor_match_attempts_persistence.py`、`tests/test_competitor_match_attempt_rescore_audit.py` 通過。
- V10.473 補背景 embedding host_health skip`allow_111_fallback=false` 會讀最近 `host_health_probes`,跳過 runtime unhealthy 的 GCP 節點(預設 20 分鐘DB fail-open避免每筆任務都等待已知壞節點 timeout路由安全不變不把背景 embedding 落 111。
- V10.472 補 GCP Ollama failover rootless 診斷:新增 `scripts/ops/diagnose_ollama_gcp_failover.sh`,可一鍵檢查 GCP-A direct、GCP-B direct、111、110:11435、110:11436 與 GCP-B `bge-m3` runtime目前輸出確認 GCP-A `11434` refused、GCP-B direct/embed OK、110:11435 502、110:11436 OK。110 無免密 sudo、GCP-A 22 refused、GCP-B SSH key denied因此 primary 修復需 GCP/SSH 或 110 root 權限;應用層維持 GCP-A → GCP-B → 111不把背景 embedding 落 111。
- V10.471 依 GCP-B `bge-m3` 實測 latency 調整 embedding timeout已部署正式環境並確認 `/health=V10.471`GCP-B `/api/embed` 三次實測約 6.4s / 7.3s / 23.5s,原本 `OLLAMA_EMBED_MAX_TIMEOUT=15` 與 host health `8s` 會誤殺慢但成功的 embedding已將背景 embedding cap 與 host health model probe timeout 預設調為 30s。正式 smoke 顯示容器內 embedding 回 1024 維、耗時 10.07s;手動 host health probe 後最新狀態為 GCP-A unhealthy、GCP-B healthy、111 healthy。路由安全不變背景 embedding 仍只跑 GCP-A/GCP-B不落 111。
- V10.470 強化 Ollama host health probe已部署正式環境並確認 `/health=V10.470`scheduler 與觀測台 host health 對 GCP-A / GCP-B 除 `/api/tags` 外,再做短 `bge-m3` `/api/embed` 實作探針;可抓出 GCP-B「tags/version 正常但 embedding runner 8s timeout」這類假健康。111 預設不做背景 embedding probe避免監控任務把 `bge-m3` 載入 fallback Mac。正式 smoke 後 `host_health_probes` 最新狀態為 GCP-A unhealthy、GCP-B unhealthy、111 healthy。
- V10.469 將背景 embedding 的 GCP-only 全失敗改為專業降級語意,已部署正式環境並確認 `/health=V10.469``allow_111_fallback=False` 時若 GCP-A/GCP-B 都不可用,開啟 failure circuit 並記 WARNING不再把可預期的背景熔斷每分鐘打成 ERROR同步 / 允許 fallback 的 embedding 全失敗仍保留 ERROR。Smoke 顯示 GCP-B `/api/version` 可用,但 `/api/embed` 仍可能 15s timeout下一步需修 GCP-A primary 與 GCP-B runner/model 負載。
- V10.468 補 Ollama import-time 防凍結與背景 embedding GCP failure circuit已部署正式環境並確認 `/health=V10.468``config.OLLAMA_HOST` / `HERMES_URL` / `EMBEDDING_HOST` 舊相容常數不再於 import 時 probe network也不會因 GCP-A/GCP-B 暫時拒連而 freeze 到 111動態 caller 仍走 `get_*()` / `OllamaService` 三主機級聯。當 `allow_111_fallback=False` 且 GCP-A/GCP-B 皆失敗時,短暫熔斷 60 秒,不重複打兩台 GCP、不落 111降低 app/scheduler 因連續 embedding timeout 造成的 log 與 worker 壓力;部署 smoke 時 GCP-B `/api/version` 已恢復 200 並成為動態路由落點GCP-A `22/11434` 仍拒連,需後續用 GCP 權限修復 primary Ollama 主機。
- V10.467 補 PChome focused exact total-price 安全通道:針對正式近門檻樣本中已確認同品牌、同品名、同規格/同入數的 3W CLINIC 粉底液 2入、花美水凝膠 3支、The Ordinary 咖啡因 EGCG 30ml、KUSSEN 屁屁膏 3入、Bone 擴香禮盒、1990 融燭燈白色款與 CANMAKE 淚袋盤,從 `exact/manual_review` 收斂為 `exact/total_price`;未放寬 `MIN_MATCH_SCORE`DASHING DIVA、唇彩、香味、色號/款式敏感商品仍維持 variant / veto 保護。Production pilot 已將 9 筆安全 SKU 送入 `rescore_accepted_current``true_low_confidence` 802→793、`rescore_accepted_current` 38→47`6101784` 即期品保留在 `true_low_confidence`。
- V10.466 修正 rescore audit duplicate 判斷:只在「最新 attempt 已是同候選 `rescore_accepted_current`」時跳過;若歷史曾 accepted、但後續 crawler 又追加低信心列,允許重新 materialize避免 Dashboard latest-state 仍停在 `true_low_confidence`。Production pilot 已將 SKU `14756069`、`11159042`、`13842560`、`8394210`、`15192547`、`10509765`、`10603780` 送入人工覆核隊列;只寫 `competitor_match_attempts``competitor_prices` / `competitor_price_history` 未變。
- V10.465 修正 embedding fallback-disabled 控制流:`allow_111_fallback=False` 時若 resolver 回 111不再直接退出或只試單台 GCP-B會強制改試尚未嘗試的 GCP-A/GCP-B背景 embedding 仍不落 111。
- V10.464 補 rescore audit 精準 SKU pilot`audit_competitor_match_attempt_rescore.py --sku` 可只掃指定 SKU再搭配 `--apply-accepted` 只把通過新版 matcher 的目標 SKU 追加到 `rescore_accepted_current` 人工覆核隊列,不寫正式價格表。
- V10.463 補 DR.WU / 達爾膚品牌 alias同規格 `DR.WU 達爾膚` 與 `DR.WU` 候選不再被當成 brandless identity review會以既有 exact_identity / total_price / price_alert_exact 閘門處理;未調整 `MIN_MATCH_SCORE`,保留 variant / hard veto 保護。
- V10.462 進一步收斂 PChome 補抓 UI 語意Dashboard 區塊標題改為「PChome 補抓產線」AI 中樞按鈕、前端確認與 API 訊息改為「補抓未搜尋 / 未搜尋補抓」,避免操作員把尚未搜尋的工作誤判成已有候選待審。
- V10.461 修正商品看板 PChome 補抓優先清單的狀態語意:尚未進入搜尋/補抓的品項改顯示「尚未搜尋」與「尚未進入 PChome 補抓」,並補前端守門測試禁止回退成籠統「待比對」,避免操作員把未搜尋誤判成已有候選待人工覆核。
- V10.460 收斂 daily/growth 圖表空白誤判與 ElephantAlpha 告警信封:`page-daily-sales.js`、`page-growth.js` 的 chart 判斷改為至少有一個非零資料點才繪製 Chart.js避免全 0 序列只畫座標軸;`resource_optimization` / `ea_escalation` 改輸出 deterministic `decision_envelope`,只使用 action_plans、CPU 實測與 hygiene evidence不再輸出空泛「48 小時效益」敘事。
- V10.459 強化 PChome `protected_existing_match` 決策封包:解析 `existing_match_conflict` 的既有候選、新候選與雙方 score寫入 `decision_envelope.evidence` / `expected_impact` / `guardrails`,並把下一步明確標成「比較既有正式候選與新候選」;仍保持 `can_auto_execute=false`,避免新候選分數較高時繞過人工覆核自動覆蓋正式價差。
- V10.458 將 OpenClaw / 競品 PPT 接上 PChome 覆核 `decision_envelope` 摘要:`competitor_intel_repository.summarize_review_decision_envelopes()` 成為共用 formatterOpenClaw 週報/日報/月報與競品簡報 data_summary / KPI slide 都讀同一份信封文字,避免策略報告與 PPT 各自翻譯覆核狀態或遺失 HITL guardrails。
- V10.457 將 PChome 覆核 `decision_envelope` 連到人工操作面Dashboard 覆核卡新增決策等級、資料品質、HITL/trace 信封摘要;`/api/export/excel/pchome-review` 匯出同步增加決策信封 ID、決策類型、建議代碼、責任人、資料品質、自動執行允許與證據摘要讓線上操作與下載檔都保留同一份 guardrails。
- V10.456 將 PChome 覆核隊列接上 `decision_envelope` contract`fetch_competitor_review_queue()` 與 `/api/pchome-review/queue` 每筆候選都輸出同一份 SKU、PChome 候選、match evidence、recommended_action、expected_impact 與 HITL guardrailsDashboard、Agent、Telegram、PPT 後續不得再各自重建比價判讀格式;同版將 review queue cache key 升到 v3避免正式環境沿用舊 payload。
- V10.455 讓 EventRouter 對 `decision_envelope` 事件走直送證據模板NemoTron / 價格比對已產生 SKU、PChome 候選、match evidence 與 HITL guardrails 時,不再進 L1/L2 AI 重新摘要避免額外模型呼叫與告警文字二次發散Telegram 決策信封同步補「標的」區塊,顯示 SKU、商品與 PChome 候選。同版補 `audit_competitor_match_attempt_rescore.py --retract-variant-accepted`,可把最新仍帶 `variant_selection_review` 的 `rescore_accepted_current` 批次追加退回 `true_low_confidence`,且不寫正式價差表。
- V10.454 補 feeder / rescore 正式寫入安全閘門matcher 若只到 `manual_review` / `identity_review` / `variant_selection_review`,例如 MOMO 多款任選唇膏對 PChome 單一款式,只能進 `true_low_confidence` 覆核,不得由 retryable replay、known identity refresh 或 rescore accepted 語意自動寫入 `competitor_prices` 正式價差。
- V10.453 補 PChome matcher 安全回收規則:新增 Herbacin 小甘菊護手霜 20ml brandless 同款 anchor修正 `EX8` 型號不可被誤解析成 `x8` 入數;新增 GONESH / 香氛固體凝膠的一側泛稱、一側明確香味或 No. 款式 veto避免近門檻 replay 把不同香味、不同入數商品錯寫成正式價差。
- V10.452 修正 PChome rescore audit 掃描口徑:`audit_competitor_match_attempt_rescore.py` 預設先取每個 SKU 最新 attempt再套用 status / reason 篩選,和 Dashboard review queue 的最新狀態一致;舊 SKU/候選考古掃描需明確加 `--include-historical-candidates`,避免已修正或已入隊商品被舊低信心紀錄重複推回報表。
- V10.451 拆分 PChome `low_score` 操作分流並補 read-only queue API比價覆核頁把近門檻可救、證據不足、低信心舊候選拆成獨立篩選repository 同步提供 `recoverable_low_score`、`true_low_confidence`、`legacy_low_score` 三個 status filter`/api/pchome-review/queue` 可直接用同一套 review_status 做 smoke / operator tools 查詢,讓回刷、人工覆核與報表不再把所有低信心候選混在一起。
- V10.450 補 PChome 覆核 fast-count UI 語意與重算可採用指標:預設全量覆核頁跳過 exact count 時,模板會顯示「約」作為快取總數提示;搜尋、分類、單一狀態仍是精準總數。`fetch_competitor_coverage()` 同步輸出 `rescore_accepted_count`,讓 Dashboard、daily/growth 與 OpenClaw 摘要能把「重算可採用待審」從一般覆核隊列拆出來。
- V10.449 修正 PChome 覆核 exact count 條件:只有預設「全部覆核、無搜尋、無分類」頁跳過 exact count只要有搜尋詞、分類篩選或單一 review status就保留精準總數避免分頁資訊失準。
- V10.448 讓 PChome 覆核「全部」頁跳過 exact count`review_status=all` 使用 shared overview cache 的待處理總數作為分頁總數提示,只查當頁 50 筆;單一狀態分流仍保留 exact count降低全量覆核頁互動成本。
- V10.447 反轉 PChome 覆核頁查詢方向review queue page 先從最新 `competitor_match_attempts` 的可覆核狀態縮小候選,再 join ACTIVE 商品與最新價,並用 `NOT EXISTS` 排除已有有效 identity_v2 正式價;避免每次「全部覆核」先掃全站 ACTIVE 商品。
- V10.446 修正 PChome 覆核頁輕量路徑的 overview timeout覆核頁總覽改讀已存在的 shared dashboard cache / stale cache沒有快取時只用目前覆核頁資料補足狀態不再現場跑 `_load_competitor_decision_overview(session)` 的重型後備 SQL。
- V10.445 補 PChome 覆核頁輕量渲染路徑:`filter=pchome_review` 不再先建完整 Dashboard `unique_items`,改為只查覆核當頁 50 筆商品、當前價、昨日價與週前價,再沿用同一張新版表格與人工覆核按鈕;降低核心比價覆核頁的全站資料負載。
- V10.444 瘦身 PChome 覆核頁查詢:`fetch_competitor_review_queue_page()` 將覆核隊列總數與當頁資料合併在單一 SQL 內取回,避免 `/?filter=pchome_review` 為 count/page 重複掃 `latest_momo`、`latest_attempt`、`valid_competitor` CTE保留狀態分流、人工覆核與正式價格寫入保護不變。
- V10.443 補 PChome rescore 人工覆核入隊:`audit_competitor_match_attempt_rescore.py --apply-accepted` 只追加 `rescore_accepted_current` attempt 進人工覆核隊列,不直接寫 `competitor_prices` / `competitor_price_history`;商品看板新增「重算可採用」分流與狀態文案,讓可救回候選先由人審確認再正式更新價差。
- V10.442 降噪 `/cicd` 舊 GitLab 探測:沒有明確啟用 `GITLAB_ENABLED=true` 與 token 時,不再打退役的 `192.168.0.110:8929` 或 SSH fallback正式 responsive smoke 造訪 `/cicd` 只呈現空 pipeline 狀態,不污染 app logs。
- V10.441 補 PChome matcher re-score audit 與商品看板原因標籤:新增 read-only `competitor_match_attempt_rescore_audit` / `scripts/audit_competitor_match_attempt_rescore.py`,可用最新版 matcher 重新分類既有 `competitor_match_attempts`,預設不寫 DB、不更新正式價格商品看板同步補蘭蔻/達特醫/hoi/Saugella/Lactacyd 等 focused matcher reason 中文標籤,讓「待對比」能拆成商品線不符、款式版本不符、可回刷或仍低信心。
- V10.439 收斂外部 BI / 資料協作入口:`/metabase`、`/grist` 正式頁維持 momo-pro 內部診斷 bridge`.env.example` 與 bi profile Grist 預設改回 `https://mo.wooo.work/grist` / `GRIST_APP_HOME_URL`,並補測試禁止 `grist.wooo.work` / `awoooi` 回流到導覽設定;外部工具頁標題字級改用新版 token 與手機 media query。
- V10.414 補市場情報 MCP fetch run readiness gate新增 `mcp_fetch_run_readiness` read-only builder、GET/POST endpoint、UI run readiness 審核面板與 deployment readiness smoke target在 run package 後檢查 command preview、receipt path、artifact path、節流/timeout/dry-run-first 與操作員 shell-only 邊界API/UI 不執行 CLI、不抓外站、不寫檔、不開 DB、不掛 scheduler只放行到人工 shell dry-run 與後續 receipt gate。
- V10.412 補市場情報 MCP fetch run package gate新增 `mcp_fetch_run_package` read-only builder、route extension、GET/POST endpoint、UI run package 審核面板與 deployment readiness smoke target將已通過的 target review 轉成操作員可覆核的 command argv preview 與 receipt path 契約API/UI 不執行 CLI、不抓外站、不寫檔、不開 DB、不掛 scheduler只放行到後續 run readiness review。
- V10.409 補市場情報 MCP fetch target review gate新增 `mcp_fetch_target_review` read-only builder、GET/POST endpoint、UI target review 審核面板與 deployment readiness smoke target讓 manual fetch handoff 通過後,先人工審核 adapter registry 公開入口、每平台節流、樣本數、timeout 與 rollback planAPI/UI 不保存 payload、不發外部 request、不開 DB、不寫入、不掛 scheduler也不會自動打開 manual fetch。
- V10.405 補市場情報 MCP manual fetch handoff gate新增 `mcp_manual_fetch_handoff` read-only builder、GET/POST endpoint、UI handoff package 審核面板與 deployment readiness smoke target將 runtime promotion package 與操作員安全確認合併成「可進人工 fetch gate 審核」的交接收據API/UI 不保存 payload、不打 health、不開 DB、不抓外站、不掛 scheduler也不會自動打開 manual fetch。
- V10.379 補市場情報 MCP runtime promotion gate新增 `mcp_runtime_promotion` read-only builder、GET/POST endpoint、UI promotion package 審核面板與 deployment readiness smoke target將 MCP activation evidence 與 runtime smoke receipt 合併成可審核的 runtime promotion packageAPI/UI 不保存 payload、不打 health、不開 DB、不抓外站、不掛 scheduler也不會自動打開人工 fetch gate。
- V10.366 補市場情報 MCP runtime smoke 收據審核:新增 `mcp_runtime_smoke_receipt` read-only builder、GET/POST endpoint、UI receipt JSON 審核面板與 deployment readiness smoke target讓操作員貼上 `/api/market_intel/mcp_readiness?execute=true&timeout=3` 的實際收據後,判斷 external/internal MCP runtime 是否可升級為已驗收API/UI 不保存 payload、不打 health、不開 DB、不抓外站、不掛 scheduler且會阻擋任何 DB write/commit/scheduler/writes 旗標或原始 readiness blocked reasons。
- V10.360 收斂瀏覽器自動開啟與 PChome 熱路徑:`tests/test_image_fetch.py` 改成 `RUN_MOMO_BROWSER_TESTS=1` 才會跑,預設 headless 且關閉 Chrome 密碼管理,避免一般 pytest 自動打開 MOMO 網站與觸發密碼允許提示scheduler Selenium 同步關閉 password manager/autofillPChome coverage/review queue 熱查詢改用 `JOIN LATERAL` 取 active 商品最新價,並補 Dashing Diva 品線召回搜尋詞。
- V10.359 導入 Browse.sh 可選爬蟲診斷與強化 MOMO/PChome 色號比對:新增 `BrowseShTool` wrapper、probe CLI 與操作手冊,讓 browse.sh 只作 selector/XHR/network trace 探勘、不進正式 schedulermatcher 補護甲油/洗手慕斯/足膜精準搜尋詞,保留小數規格,並對唇釉、妝前乳、素顏霜等顯性色號/色系不一致候選做 hard veto避免同系列不同色號污染正式價差。
- V10.358 補市場情報 MCP 啟用證據審核:新增 `mcp_activation_evidence` read-only builder、GET/POST endpoint、UI redacted evidence 審核面板與 deployment readiness smoke target讓操作員貼上 env/health/router/telemetry/fallback 證據後判斷能否補齊 external/internal MCP runtime 缺口API/UI 不保存 payload、不打 health、不啟動 MCP、不執行 docker/SSH、不開 DB、不抓外站、不掛 scheduler且會阻擋真實 secret 字串與任何 DB write/fetch/scheduler 證據。
- V10.357 補市場情報 MCP 完整度稽核:新增 `mcp_completion_audit` read-only builder、GET endpoint、UI 面板與 deployment readiness smoke target彙整外部 MCP design/runtime、內部 tool contract/runtime、activation runbook 與 fetch gate 狀態API/UI 不啟動 MCP、不打 health、不執行 docker/SSH、不開 DB、不寫檔、不抓外站、不掛 scheduler。
- V10.356 補市場情報 candidate queue review AI summary Telegram dispatch report catalog record final closeout gate新增 read-only report catalog record final closeout builder、POST endpoint、UI 按鈕與 deployment readiness smoke target在 archive summary gate 後覆核 catalog record identity、artifact traceability、sections、DB commit/post-write smoke、pipeline complete 與無後續 follow-upAPI/UI 不讀 approval/Telegram token、不呼叫 LLM、不產報表、不派送 Telegram、不開 DB、不寫檔、不執行 CLI、不寫 catalog record、不 commit、不更新 review_state、不掛 scheduler。
- V10.355 補市場情報 candidate queue review AI summary Telegram dispatch report catalog record archive summary gate新增 read-only report catalog record archive summary builder、POST endpoint、UI 按鈕與 deployment readiness smoke target在 archive gate 後整理 catalog record identity、artifact traceability、DB commit/post-write smoke、archive manifest/retention policy 與後續 final closeout separate gateAPI/UI 不讀 approval/Telegram token、不呼叫 LLM、不產報表、不派送 Telegram、不開 DB、不寫檔、不執行 CLI、不寫 catalog record、不 commit、不更新 review_state、不掛 scheduler。
- V10.354 補市場情報 candidate queue review AI summary Telegram dispatch report catalog record archive gate新增 read-only report catalog record archive builder、POST endpoint、UI 按鈕與 deployment readiness smoke target在 closeout gate 後審核 closeout/commit/run receipt/writer output/post-write smoke/backup 封存證據、archive manifest/retention policy 與後續 archive summary separate gateAPI/UI 不讀 approval/Telegram token、不呼叫 LLM、不產報表、不派送 Telegram、不開 DB、不寫檔、不執行 CLI、不寫 catalog record、不 commit、不更新 review_state、不掛 scheduler。
- V10.353 補市場情報 candidate queue review AI summary Telegram dispatch report catalog record closeout gate新增 read-only report catalog record closeout builder、POST endpoint、UI 按鈕與 deployment readiness smoke target在 commit gate 後審核 catalog record identity、DB commit/post-write smoke 證據、操作員 closeout 確認與後續 archive separate gateAPI/UI 不讀 approval/Telegram token、不呼叫 LLM、不補產報表、不派送 Telegram、不開 DB、不寫檔、不執行 CLI、不寫 catalog record、不 commit、不更新 review_state、不掛 scheduler。
- V10.352 補市場情報 candidate queue review AI summary Telegram dispatch report catalog record commit gate新增 read-only report catalog record commit builder、POST endpoint、UI 按鈕與 deployment readiness smoke target在 run receipt 後審核外部 CLI catalog record DB commit、post-write smoke、操作員 commit gate 確認與後續 closeout separate gateAPI/UI 不讀 approval/Telegram token、不呼叫 LLM、不補產報表、不派送 Telegram、不開 DB、不寫檔、不執行 CLI、不寫 catalog record、不 commit、不更新 review_state、不掛 scheduler。
- V10.351 補市場情報 candidate queue review AI summary Telegram dispatch report catalog record run receipt新增 read-only report catalog record run receipt builder、POST endpoint、UI 按鈕與 deployment readiness smoke target在 run readiness 後審核外部 CLI writer output、catalog record key/hash、DB commit receipt 與 post-write smokeAPI/UI 不讀 approval/Telegram token、不呼叫 LLM、不補產報表、不派送 Telegram、不開 DB、不寫檔、不執行 CLI、不寫 catalog record、不 commit、不更新 review_state、不掛 scheduler。
- V10.348 補市場情報 candidate queue review AI summary Telegram dispatch report catalog record run readiness新增 read-only report catalog record run readiness builder、POST endpoint、UI 按鈕與 deployment readiness smoke target在 run package 後檢查 payload manifest、manual CLI command、backup/dry-run、run receipt 與 postwrite smoke 條件API/UI 不讀 approval/Telegram token、不呼叫 LLM、不補產報表、不派送 Telegram、不開 DB、不寫檔、不執行 CLI、不寫 catalog record、不更新 review_state、不掛 scheduler。
- V10.347 補市場情報 candidate queue review AI summary Telegram dispatch report catalog record run package新增 read-only report catalog record run package builder、POST endpoint、UI 按鈕與 deployment readiness smoke target在 record write gate 後整理 payload manifest、CLI command bundle、backup/dry-run trace 與後續 run readiness separate gateAPI/UI 不讀 approval/Telegram token、不呼叫 LLM、不補產報表、不派送 Telegram、不開 DB、不寫檔、不執行 CLI、不寫 catalog record、不更新 review_state、不掛 scheduler。
- V10.344 補市場情報 candidate queue review AI summary Telegram dispatch report catalog record write gate新增 read-only report catalog record write builder、POST endpoint、UI 按鈕與 deployment readiness smoke target在 write preflight 後檢查 catalog record key/schema/hash trace、operator dry-run、backup 與 commit separate gateAPI/UI 不讀 approval/Telegram token、不呼叫 LLM、不補產報表、不派送 Telegram、不開 DB、不寫檔、不寫 catalog record、不更新 review_state、不掛 scheduler。
- V10.342 補市場情報 candidate queue review AI summary Telegram dispatch report catalog write preflight新增 read-only report catalog write preflight builder、POST endpoint、UI 按鈕與 deployment readiness smoke target在 report catalog index 後整理 catalog record identity、write source trace、record schema preflight 與 runtime safety只放行到後續 report catalog record write gateAPI/UI 不讀 approval/Telegram token、不呼叫 LLM、不補產報表、不派送 Telegram、不開 DB、不寫 catalog preflight file、不寫 catalog record、不更新 review_state、不掛 scheduler。
- V10.339 補市場情報 candidate queue review AI summary Telegram dispatch report catalog index新增 read-only report catalog index builder、POST endpoint、UI 按鈕與 deployment readiness smoke target在 report catalog handoff 後整理 catalog index identity、handoff source trace、index manifest 與 runtime safety只放行到後續 report catalog write preflight gateAPI/UI 不讀 approval/Telegram token、不呼叫 LLM、不補產報表、不派送 Telegram、不開 DB、不寫 catalog index file、不寫 catalog record、不更新 review_state、不掛 scheduler。
- V10.338 補市場情報 candidate queue review AI summary Telegram dispatch report catalog handoff新增 read-only report catalog handoff builder、POST endpoint、UI 按鈕與 deployment readiness smoke target在 report archive summary 後整理 catalog identity、artifact manifest、section keys 與 hash traceability只放行到後續 report catalog index gateAPI/UI 不讀 approval/Telegram token、不呼叫 LLM、不補產報表、不派送 Telegram、不開 DB、不寫 catalog record、不更新 review_state、不掛 scheduler。
- V10.335 補市場情報 candidate queue review AI summary Telegram dispatch report archive summary新增 read-only report archive summary builder、POST endpoint、UI 按鈕與 deployment readiness smoke target在 report archive 後整理 report identity、archive traceability、integrity review 與 runtime safety sections只放行到後續 report catalog handoff gateAPI/UI 不讀 approval/Telegram token、不呼叫 LLM、不補產報表、不派送 Telegram、不開 DB、不寫檔、不更新 review_state、不掛 scheduler。
- V10.334 強化 MOMO/PChome 核心比價第二波matcher 補常見品牌 alias、任選/平輸/國別 noise 收斂、刀把/刀片/刀頭等件數解析與系列衝突硬否決,避免 Gillette/Schick 同品牌不同系列或刀片數被誤當同款;新增近門檻候選重新評分流程,會把舊 low_score 中 0.70 以上且非 hard veto、有 PChome product_id 的候選先批次重評,再補抓高價未配對商品;商品看板新增 PChome 補抓產線狀態卡,顯示 run id 階段、成功/低信心/無結果/挑品寫入與錯誤,不再讓核心比價補抓變成黑盒。
- V10.333 補市場情報 candidate queue review AI summary Telegram dispatch report archive新增 read-only report archive builder、POST endpoint、UI 按鈕與 deployment readiness smoke target在 report closeout 後審核 archive/closeout/receipt/report output artifact path、hash/章節、archive manifest、retention policy 與後續 archive summary separate gateAPI/UI 不讀 approval/Telegram token、不呼叫 LLM、不補產報表、不派送 Telegram、不開 DB、不寫檔、不更新 review_state、不掛 scheduler。
- V10.332 補市場情報 candidate queue review AI summary Telegram dispatch report closeout新增 read-only report closeout builder、POST endpoint、UI 按鈕與 deployment readiness smoke target在 report run receipt 後審核 closeout artifact、receipt/report artifact path、hash/章節覆核、後續 report archive separate gate 與 runtime boundaryAPI/UI 不讀 approval/Telegram token、不呼叫 LLM、不補產報表、不派送 Telegram、不開 DB、不寫檔、不更新 review_state、不掛 scheduler。
- V10.331 強化 PChome 比價 matcher 邊界:正式端 pilot 先刷新 30 筆過期 identity_v2、補抓 15 筆高價未配對 SKU確認 structured diagnostics 開始寫入;針對「同品牌、同核心多組件、無任何否決理由、價格正常」但因規格文字不完整卡在 0.74x 的候選,新增 strong_component_line_match 窄門補分,避免 Gennies 類完整套組被誤留在低信心,同時維持雙入組對單品、容量衝突、不同品牌與補充瓶硬否決。
- V10.330 補市場情報 candidate queue review AI summary Telegram dispatch report run receipt新增 read-only report run receipt builder、POST endpoint、UI 按鈕與 deployment readiness smoke target在 report run readiness 後審核人工/獨立 job 產出的 report receipt、artifact path/hash、必要章節、summary hash 與 runtime boundaryAPI/UI 不讀 approval/Telegram token、不呼叫 LLM、不補產報表、不派送 Telegram、不開 DB、不寫檔、不更新 review_state、不掛 scheduler。
- V10.329 優化 `/growth_analysis` 冷快取策略source fingerprint 未變時,成長分析共享快取由 30 分鐘延長為 6 小時有效;每日匯入仍會主動清除快取,避免資料更新後沿用舊圖表,同時降低正式端重啟或冷 worker 重新掃 `realtime_sales_monthly` 的 14 秒級等待。
- V10.328 強化 MOMO/PChome 核心比價準確性第一波:補高頻品牌 alias、中文商品線 bigram 訊號、保健/包裝同義單位與買送件數解析,搜尋詞改為品牌/核心/主規格三層PChome 比對嘗試與正式快照補存 URL、圖片、庫存與結構化 diagnostics商品列表用 tone 分流顯示尚未搜尋、低信心、身份否決、單位價與過期狀態,不再把不同問題全部壓成灰色待比對;同步持久化首頁 / PChome coverage 熱路徑索引,避免重開機後慢查詢回歸。
- V10.327 補 OpenClaw fallback 可觀測性週報、月報、Meta、日報洞察、每日報告的 Gemini/NIM 備援 caller 納入 caller registry、AI 觀測台 agent group 與 Telegram 狀態統計,並補 MCP collector Ollama-first regression test避免 fallback 真實使用量在觀測層被歸類成未知或漏算。
- V10.326 補市場情報 candidate queue review AI summary Telegram dispatch report run readiness新增 read-only report run readiness builder、POST endpoint、UI 按鈕與 deployment readiness smoke target在 report run package 後整理 report generation readiness manifest、manual report command boundary、artifact path gate 與後續 report run receipt gateAPI/UI 不讀 approval/Telegram token、不呼叫 LLM、不派送 Telegram、不開 DB、不寫檔、不產報表、不更新 review_state、不掛 scheduler。
- V10.325 收斂 Gemini 主路徑OpenClaw 週/月/meta/日報洞察、Telegram PPT 分析與 MCP fallback 全部改成先走 OllamaService 的 GCP-A → GCP-B → 111 三主機級聯Gemini 只在 Ollama/NIM 不可用後作備援。Elephant Alpha resource_optimization 告警補上待處理 action_plans 焦點列表,避免只報隊列數字卻沒有可執行對象。
- V10.324 補市場情報 candidate queue review AI summary Telegram dispatch report run package新增 read-only report run package builder、POST endpoint、UI 按鈕與 deployment readiness smoke target在 report input 後整理 run package contract、evidence refs、package sections 與後續 report run readiness gateAPI/UI 不讀 approval/Telegram token、不呼叫 LLM、不派送 Telegram、不開 DB、不寫檔、不產報表、不更新 review_state、不掛 scheduler。
- V10.323 收斂市場情報 seed writer token hardening drift正式端 service smoke 已確認 `seed_writer_cli_status` 不再回吐 `approval_token_hint`、不洩漏環境 token輸出補 `api_reads_approval_token=false`、`api_executes_cli=false`、`api_writes_database=false`,讓 API/CLI 邊界可被 regression test 與 smoke 明確驗證。
- V10.322 修正 Telegram 決策/審核推播舊入口:`price_decision_notify()` 改用 `send_telegram_with_result()` 統一套用 HTML sanitizer 與多 chat 結果彙整,並補齊 `price_decision(report_url=...)` 相容RAG awaiting review 推播改用正確 `chat_ids=[...]` 呼叫,避免 Stage 4 人工審核按鈕因參數名錯誤完全送不出去。
- V10.321 修正 Telegram HTML 發送格式:所有 `sendMessage` / `sendPhoto` caption 在 HTML parse mode 送出前會把 `<br>` / `<br/>` / `<BR />` 統一轉成換行,避免 Telegram Bot API 回 `Unsupported start tag "br"` 造成告警或報告送出失敗。
- V10.320 補市場情報 candidate queue review AI summary Telegram dispatch report input新增 read-only report input builder、獨立 report route extension、UI 按鈕與 deployment readiness smoke target在 archive summary 後整理 report input sections、report contract、message evidence 與 dispatch audit traceabilityAPI/UI 不讀 approval/Telegram token、不呼叫 LLM、不派送 Telegram、不開 DB、不寫檔、不產報表、不更新 review_state、不掛 scheduler。
- V10.319 補市場情報 candidate queue review AI summary Telegram dispatch archive summary新增 read-only archive summary builder、POST endpoint、UI 按鈕與 deployment readiness smoke target在 Telegram dispatch archive 後整理 message identity、dispatch audit、artifact manifest 與後續 report input sectionsAPI/UI 不讀 approval/Telegram token、不呼叫 LLM、不派送 Telegram、不開 DB、不寫檔、不更新 review_state、不掛 scheduler。
- V10.318 收緊 Elephant Alpha HITL 告警治理:`ea_escalation` 只有真正含 SKU/價格比較的 actions 才排成 TOP 待審 SKU 卡片;非 SKU 診斷改為「待確認事項」,並用測試鎖住價格類低信心但無 DB/Hermes 實證時只 suppress、不寫 human_review、不發 Telegram避免空泛告警打擾人工審核。
- V10.317 修正 PChome 比價覆蓋率分子:`fetch_competitor_coverage()` 的 valid_matches 改成 `ACTIVE + 有 MOMO 最新價` 商品與有效 PChome `identity_v2` 價格的交集,不再把非活躍或無 MOMO 現價的舊 competitor_prices 列入覆蓋率,避免 daily/growth/PPT/AI 報表高估比價資料品質。
- V10.315 修正競品簡報/報表指定日期取價:`fetch_competitor_comparison_results()` 在有 start/end date 時改讀 `competitor_price_history` 的期間快照MOMO 價格也取期間結束前最新價;沒有指定日期才使用目前有效 `competitor_prices`,避免把今天的 PChome 快取價塞回歷史 daily/growth/PPT 判讀。
- V10.314 擴大 PChome 候選池與搜尋韌性PChome 搜尋 API 改為依 limit 掃多頁並對 429/5xx/timeout 做有限重試feeder 預設每個商品最多 5 組搜尋詞、每詞 20 候選、2 頁,且搜尋清理不再刪掉括號/方括號內的品牌與規格,讓正確候選更有機會進 matcher而不是長期停在「待對比」。
- V10.312 強化 PChome 商品身份比對防錯配matcher 開始解析 mg/mcg 劑量、件組套組與多規格集合60ml+150ml vs 60ml+20ml、10mg vs 20mg、10片 vs 10盒、精華 vs 化妝水都會進硬否決或單位價覆核,不再靠單一規格重疊放行;覆核診斷同步新增「劑量差異」標籤,降低核心比價錯配污染 daily/growth/PPT/AI 分析。
- V10.311 統一競品價差語意:`fetch_competitor_comparison_results()`、competitor PPT 與 OpenClaw competitor prompt 全部改用 `MOMO - PChome`,正值代表 MOMO 較貴 / PChome 低價壓力,負值代表 MOMO 價格優勢;避免 daily/growth 顯示價格壓力但 PPT/AI 反向解讀。
- V10.310 強化 MOMO/PChome 核心比價閉環PChome feeder 搜尋候選只有強同款 `0.90` 才提前停止,避免第一個 0.76 次佳候選卡掉後續精準搜尋詞;人工否決的候選會被跳過並改挑下一個候選,不再讓已否決商品長期阻塞同 SKU。人工 `reject_identity`、`unit_price_required`、`needs_research` 會立即讓同候選正式 `competitor_prices` 過期Dashboard 即使尚有舊價也不再顯示正式總價差;手機版比價覆核欄位標籤、覆核按鈕冒泡與候選證據顯示同步修正。
- V10.308 修正商品列表 PChome 比價閉環狀態:`manual_rejected`、`manual_unit_price_required`、`manual_needs_research` 不再掉回籠統「待比對」,改顯示「人工已否決 / 人工標記單位價 / 人工要求補搜尋」與後續 feeder 行為說明,避免人工覆核後 UI 看起來像沒有處理。
- V10.307 將 PChome 人工覆核成效接進 daily/growth/PPT 共用資料出口:`fetch_competitor_coverage()` 讀取 `competitor_match_reviews` 最新決策,輸出人工採用、人工否決、人工單位價與採用率;`daily_sales` 與 `growth_analysis` 的比價資料品質區塊直接顯示這些閉環指標,讓報表與簡報不只看待審數,也能看人工處理成效。
- V10.305 將 PChome 人工覆核回饋接回 feeder下一輪搜尋若命中已被 `reject_identity` 否決的同一候選,會記錄 `manual_rejected` 並跳過正式寫入;已被標記 `unit_price_required` 的候選只保留單位價比較,不寫入正式總價差;人工 `accept_identity` 可保守覆蓋低分門檻但會打 `manual_review/manual_accept` 標籤,讓核心比價閉環可被後續報表與簡報追蹤。
- V10.304 補 PChome 比價人工覆核決策閉環:新增 `competitor_match_reviews`、`/api/pchome-review/<sku>/decision` 與商品看板覆核列「採用同款 / 否決候選 / 標記單位價」動作;只有人工採用同款才寫入 `competitor_prices` + `competitor_price_history`,否決與單位價標記只追加 manual attempt 並關閉本輪覆核,避免錯配污染核心價差。
- V10.302 補 PChome 比價覆核匯出與診斷原因:`filter=pchome_review` 每筆覆核把 matcher `reasons=` 翻成品牌不符、商品線不符、容量差異、組合差異、需單位價、價差極端等可行動標籤;新增 `/api/export/excel/pchome-review` 匯出完整覆核隊列、人工處置、候選 PChome、單位價比較與原始診斷避免核心比價只停在籠統「待對比」。
- V10.301 補市場情報 candidate queue review AI summary Telegram dispatch gate新增 `/api/market_intel/manual_sample_review/candidate_queue_review_ai_summary_persistence_telegram_dispatch_gate` 與 UI 按鈕,在 summary persistence closeout 後檢查 Telegram 訊息契約、channel label、artifact path、token 外洩風險與後續 run package promotionAPI/UI 仍不讀 approval/Telegram token、不呼叫 LLM、不開 DB、不寫檔、不派送 Telegram、不掛 scheduler。
- V10.300 補商品看板比價覆核狀態分流:`filter=pchome_review` 新增全部、需單位價、身份否決、低信心、價格過期、找不到同款 segmented 篩選與分頁保留參數,讓 6,000+ 筆覆核隊列能依 matcher 診斷類型分批處理;同步修正覆核列表表頭/分頁連結狀態保留。
- V10.299 補市場情報 candidate queue review AI summary persistence run closeout新增 `/api/market_intel/manual_sample_review/candidate_queue_review_ai_summary_persistence_run_closeout` 與 UI 按鈕,在 receipt 通過後收尾 metadata_json persistence gate確認 closeout artifact、操作員確認與後續 Telegram dispatch 必須另開 gateAPI/UI 仍不讀 approval token、不執行 CLI、不連 DB、不寫 `metadata_json`、不派送 Telegram、不掛 scheduler。
- V10.298 補市場情報 candidate queue review AI summary persistence run receipt新增 `/api/market_intel/manual_sample_review/candidate_queue_review_ai_summary_persistence_run_receipt` 與 UI 按鈕,審核操作員貼回的 metadata_json CLI writer output、post-write smoke、dedupe key、summary payload hash、artifact path 與 token 外洩風險API/UI 仍不讀 approval token、不執行 CLI、不連 DB、不寫 `metadata_json`、不派送 Telegram、不掛 scheduler。
- V10.297 將 PChome 單位價覆核隊列接回商品看板第一屏KPI 顯示待處理/需單位價覆核數,焦點區列出候選 PChome 商品、候選價、match score 與人工動作;新增 `filter=pchome_review` 的比價覆核隊列,讓使用者可直接進入待處理 SKU不再只在 daily/growth/PPT 摘要看到統計。
- V10.296 補核心 MOMO/PChome 比價第三層語意與覆核閉環:同核心商品但買送、套組、件數不同且只有單一基礎規格時標記 `unit_comparable`,只寫入 `competitor_match_attempts`商品看板、daily/growth 報表、OpenClaw/PPT 摘要共用 `competitor_intel_repository` 的覆核隊列,顯示「需單位價比較」、候選商品、候選 PChome 價格與單位價換算證據;多容量/多品項套組仍保持不可比較,避免把不同販售組合直接寫進正式總價差。
- V10.289 重排 Elephant Alpha L3 HITL `ea_escalation` Telegram 告警:改成專業 incident brief 格式分成決策狀態、背景摘要、風險摘要、TOP 待審 SKU 與建議處置;價格行動會拆出 MOMO/PChome 價格、價差、人工處置與 PChome ID避免長 bullet 難讀。
- V10.284 關閉 Code Review Hermes LLM scan 預設路徑Step 2 改 deterministic fast static scan不再讓部署後先卡三段 Ollama timeout若需要 LLM scan 可用 `CODE_REVIEW_HERMES_LLM_SCAN_ENABLED=true` 顯式開啟,仍只走本地矩陣、不走 Gemini。
- V10.283 將 Code Review Hermes scan 收斂為 fast compact prompt預設 2 檔 × 900 字、輸出 384 tokens仍走 GCP-A → GCP-B → 111 本地矩陣,避免部署後 code_review_hermes 先卡三段 timeout。
- V10.282 補齊 Code Review Hermes scan 本地模型矩陣:掃描階段也走 GCP-A `qwen2.5-coder:7b` → GCP-B `gemma3:4b` → 111 `hermes3:latest`,避免 `hermes3` 在三主機各卡 35s 後只留下 errorHermes scan 不會啟用 Gemini。
- V10.281 強化 Code Review OpenClaw 本地備援矩陣:主機順序仍為 GCP-A → GCP-B → 111但改成 GCP-A `qwen2.5-coder:7b`、GCP-B `gemma3:4b`、111 `hermes3:latest`,三段本地 Ollama 全失敗後才允許 Claude/Gemini 備援。
- V10.279 收斂 Code Review Ollama-first 路徑OpenClaw assessment 預設改 `qwen2.5-coder:7b` + 45s/host timeoutHermes scan 改 compact snippet + 35s/host timeout避免三主機各卡 120s 後被迫觸發 Gemini 備援。
- V10.278 補 PChome 競價摘要 30 分鐘共享快取與 feeder/backfill 主動清除,並新增市場情報 `candidate_queue_review_ai_summary_preflight` 預覽 gateAPI 只檢查未來摘要輸入與 Ollama-first/Gemini-backup-only policy不呼叫 LLM、不派 Telegram、不寫 DB、不掛 scheduler。
- V10.276 修正 ElephantAlpha 價格類 Hermes prefetch timeout`price_drop` / `market_opportunity` trigger 直接把 SQL 命中的 MOMO / PChome 價差實證轉成 HITL action lines完整 Hermes LLM prefetch 預設關閉;無 DB 實證仍只記 suppressed telemetry / cooldown不寫 `human_review`、不發空 Telegram。
- V10.266 強化核心 MOMO/PChome 比價鏈路:新增 `marketplace_product_matcher.py` 身份比對、只讓 `identity_v2` 且分數 ≥ 0.76 的高信心配對進 Dashboard/AI/Excel/Daily/Growth/PPT並建立 `competitor_intel_repository.py` 統一圖表與簡報資料出口;同品牌但不同型號、不同組數、套組/單品或多品項不一致會進待審,不進正式比價。
- V10.267 專業化 ElephantAlpha `resource_optimization` 告警:不再讓 LLM 生成「48 小時預期效益 / 已執行」敘事,改由程式量測 action queue、P1/P2、pending_review、逾時項目與 CPU load單純 backlog 不發 Telegram只有可行動資源壓力才寫 `ai_insights(resource_pressure)` 並發送量測型告警。
- V10.254 續補 `/growth_analysis` 快取命中效能PostgreSQL source fingerprint 加 60 秒短 TTL匯入 realtime_sales_monthly 後同步清除 growth shared cache 與短快取,避免快取命中仍頻繁掃大表 COUNT。
- V10.253 修正 Elephant Alpha L3 HITL 空告警:價格類與資源調配低信心事件若沒有 Hermes/實證資料,只記 suppressed telemetry 與 cooldown不寫 pending human_review、不發 Telegram`resource_optimization` 會保留 queue/load 原始指標供追查。
- V10.251 修正 OpenClaw Q&A 備援遙測Ollama 主路徑仍為 GCP-A → GCP-B → 111Gemini 只記為 `openclaw_qa_gemini_fallback`NIM 只記為 `openclaw_qa_nim`AI Calls 會把 legacy `openclaw_qa + gemini` 標成 Gemini 備援,避免再次誤判 Gemini-first。
- V10.251 穩定 `/growth_analysis` 正式站速度:成長分析快取從單 worker memory 擴充為 `data/growth_analysis_cache.pkl` 跨 worker 共享快取,避免 Gunicorn 冷 worker 偶發掃明細表造成 5 秒級 TTFB補 `tests/test_cache_manager.py` 覆蓋 shared file roundtrip 與清除行為。
- V10.249 收斂 `/observability/ppt_audit_history` 手機與平板第一屏密度:將 4 個產線訊號從 hero 內移出成獨立狀態列,手機版維持 2 欄狀態卡並降低 hero 卡片間距;本機 10 個 AI 觀測台頁面 rendered visual contract 全數通過PPT 頁 hero 高度 desktop/tablet/mobile 為 214/361/398px。
- V10.246 強化 `/observability/ppt_audit_history` 視覺 QA runtime 可讀性:功能開關、轉檔器與視覺模型改成中文 checklistVision QA 狀態卡直接顯示 runtime 就緒資訊DB 產出狀態統一為「已產出」。
- V10.245 重整 `/observability/ppt_audit_history` 首屏資訊階層:改成簡報操作摘要、最新可預覽簡報、下一步動作與自適應報表類型 segmented grid產線覆蓋矩陣改為下方驗收明細避免一進頁只看到大量「產線狀態」或類型按鈕右側溢出。
- V10.242 修正 `/metabase`、`/grist` 外部工具入口:全域導覽固定回 momo-pro 內部橋接頁,避免資料協作錯連其他專案站;入口頁補路由狀態、設定診斷與可用替代分析入口,降低空白頁誤判。
- V10.221 補 `/observability/ppt_audit_history` AiderHeal 背景任務可見性:正在修復中的簡報會顯示於產線頁,並提供 JSON 狀態端點讓派工後即時刷新,避免重新整理後不知道是否已在修。
- V10.218 補 `/observability/ppt_audit_history` AiderHeal 去重鎖:同一份簡報已在背景修復時,再次點擊會回「已在執行中」,避免重複開 SSH / 模型 / git 修復流程。
- V10.217 讓 `/observability/ppt_audit_history` 的 AiderHeal 派工改為非阻塞背景任務:頁面立即回「已排入」,修復工作在背景執行,避免瀏覽器與 Gunicorn worker 等 SSH、模型與 git push 到超時。
- V10.216 修正 `/observability/ppt_audit_history` 的 AiderHeal 派工斷點:失敗簡報即使只有 `issues_found` 診斷摘要也能一鍵送修,並修正 `execute_code_fix` 參數與 dict 回傳解析,避免按鈕 400/500。
- V10.215 強化 `/observability/ppt_audit_history` 視覺問題追蹤:將 `issues_found` 拆成投影片、問題類型、問題文字與回放入口,新增「視覺問題追蹤」面板,讓問題簡報能直接定位與預覽。
- V10.213 補 `/observability/ppt_audit_history` 視覺 QA 診斷摘要:審核歷史與 Action Queue 直接顯示 `ppt_audit_results.issues_found` 的投影片問題,讓「有問題」可追查,不再只剩問題數或空白錯誤欄。
- V10.212 修正 PPT 視覺 QA 的 Ollama 三主機 fallback當 Primary/Secondary request timeout 超過 unhealthy TTL 時,第三輪仍強制打 111 final fallbackPPT 截圖送模型前轉輕量 JPEG、縮小輸出 token降低單檔審核耗時。
- V10.211 補 `/observability/ppt_audit_history` 全類型視覺 QA審核歷史不再限 daily頁面新增「立即視覺 QA」非阻塞補跑結果寫入 `ppt_audit_results`;模型失敗時也保留 slide error避免產線狀態只剩空白。
- V10.210 補 `/observability/ppt_audit_history` 審核歷史同頁回放:每筆 daily 視覺審核紀錄的動作欄新增「回放」按鈕,沿用 PDF 預覽抽屜並保留下載/開新頁,讓問題追查不必再回檔案表找簡報。
- V10.208 修正 `/observability/ppt_audit_history` 同頁預覽抽屜 selectorModal 標題改用獨立 `data-ppt-preview-modal-title`,避免與多個預覽連結的資料屬性衝突。
- V10.207 強化 `/observability/ppt_audit_history` 同頁線上預覽:所有可預覽簡報按鈕改為開啟頁內 PDF 預覽抽屜,保留開新頁與下載,降低產線頁來回跳轉成本並改善手機操作。
- V10.205 補 `/observability/ppt_audit_history` 本頁批次 PDF 預熱Preview Workbench 可一鍵預熱頁面上尚未快取的 PPTX沿用單檔 JSON 端點逐一建立 PDF 快取並即時更新狀態。
- V10.203 補 `/observability/ppt_audit_history` 單檔 PDF 預熱操作:未快取的可預覽 PPTX 會顯示「預熱 PDF」透過 JSON 端點建立 PDF 快取並即時更新頁面狀態。
- V10.201 強化 `/observability/ppt_audit_history` 線上預覽可診斷性:產線清單不觸發轉檔即可顯示 PDF 預覽快取狀態Pipeline Health、Preview Workbench 與已產檔案表同步標記「PDF 快取 / 首次轉檔」。
- V10.199 讓 `/observability/ppt_audit_history` Action Queue 可直接處理異常:待補齊與異常優先項目新增單一報表「重跑」按鈕,透過既有非阻塞背景產線排入指定 report_type。
- V10.197 強化 `/observability/ppt_audit_history` Action Queue新增「異常優先」lane將產出失敗、PPTX 檔案異常、視覺 QA 失敗拉到最前面,並顯示錯誤訊息與可預覽入口。
- V10.196 補 `/observability/ppt_audit_history` Action Queue把待補齊、可預覽、視覺 QA、DB 寫入集中成工作隊列,讓使用者不用在多張卡與表格間找下一個處理點。
- V10.194 重整 `/observability/ppt_audit_history` 產線資訊階層:新增 Pipeline Health、五段式流程階段、排程/覆蓋/DB/預覽/視覺 QA 狀態摘要,讓「已產生」改為可判斷的目標產生、其他版本、待排程補齊等狀態。
- V10.192 補 `/observability/ppt_audit_history` 最近可預覽簡報 workbench最新 4 份 PPT 直接在控制台下方提供線上預覽與下載,降低使用者找檔案的操作成本;完整檔案清單仍保留在下方表格。
- V10.190 補 `/observability/ppt_audit_file/<filename>` 站內線上預覽PPTX 由 LibreOffice 轉 PDF 快取後以 iframe 預覽,保留原始 PPTX 下載Dockerfile 加 `libreoffice-impress`compose 預設啟用 `PPT_VISION_ENABLED=true`PPT 產線頁新增視覺 QA 停用原因與更精簡的控制台式排版。
- V10.188 補強 `/observability/ppt_audit_history` PPT 視覺 QA 產線:頁面明確呈現每日、每週、每月、每季、每半年、每年定期產出節奏,並顯示 `ppt_generation_runs` DB 寫入紀錄;保留自動補齊缺漏與資料庫/檔案覆蓋狀態。
- V10.187 修正 `/daily_sales`、`/growth_analysis` 圖表空白Chart JSON 改從 `<template>.content.textContent` 讀取,補空資料診斷狀態;成長分析改用 realtime 明細新鮮度覆蓋過期月結摘要,並為 growth cache 加入資料指紋。
- V10.151 接續前端 V3 全站 UI/UX廠商缺貨 `/vendor-stockout/vendor-management`、`/vendor-stockout/send-email`、`/vendor-stockout/history` 改走新版 `ewoooc_base.html` shell 與 `page-vendor-tools.css`,移除舊紫藍 navbar/live route。
- V10.151 補 `/abc_analysis/detail` 新版 ABC 詳情頁與安全 loading state移除 raw HTML fallback資料表維持正式快取資料來源與匯出連結。
- V10.151 補 `/login` 新版登入頁暖紙背景、點陣視覺、EwoooC 品牌、手機版 390px 無水平 overflow。
- V10.151 本機全站 responsive overflow guard 通過 147/147`?ui=legacy` 入口已不再回到舊 `dashboard.html` / `edm_dashboard.html` / vendor legacy templates。
- 新版設計系統資產已落到正式 Flask static path`web/static/css/ewoooc-tokens.css`、`web/static/css/ewoooc-shell.css`、`web/static/css/ewoooc-dotmatrix.css`、`web/static/css/page-*.css` 與對應 `web/static/js/page-*.js`。
- V3 page-level 資產已補做設計規範清理:移除 UI 表面殘留 radial-gradient / pure-white rgba / `bg-white` headerAI 推薦頁 keyword 狀態改用語意 class。
- `ewoooc_base.html` 補 `extra_head` / `content` / `extra_scripts` 相容 block支援新版包混用 block 命名,避免頁面空白或互動 JS 不輸出。
- Base CSS 載入順序已補齊 `ewoooc-tokens-v2-alias.css`,符合 V3 spec 的 tokens → alias → shell → dotmatrix 順序。
- `_ewoooc_shell.html` 更新為 V3 側欄結構,保留正式路由連結與 AI 觀測台完整導覽 label。
- 高風險替換已退回:`dashboard_v2.html` 與 `templates/admin/*` 觀測台頁保留現行真實功能版,拒絕使用會移除 PChome / AI 挑品 / 歷史價格 / 觀測台真實資料的 prototype 空殼。
- AI 觀測台 CSS canonical 與 Flask mirror 已通過同步檢查:`./scripts/quick_review.sh --check-observability-css`。
- AI 觀測台 UI guard 已更新為 V3 token 化規範,不再要求舊版 sidebar 漸層片段,並通過 `./scripts/quick_review.sh --observability-ui`。
- 新增 ADR-036FastAPI 可作為 strangler migration 中期方向,但不得作為前端 V3 前置條件;後端重構先抽 service 與補 contract不做 Flask→FastAPI 大爆炸。
- `/sales_analysis` 修正 V3 首次進頁 JSON context 合約:`category_data` 與模板 fallback 補齊,避免 Jinja `Undefined` 進入 `tojson` 造成 error handler。
- 本機瀏覽器 QA 完成:`/sales_analysis`、`/daily_sales`、`/monthly_summary_analysis`、`/ai_recommend`、`/auto_import`、`/vendor-stockout/*` 均載入 V3 shell、無錯誤 banner、console error 0。
- 正式環境已推版:白名單同步 55 個 V3 runtime 檔案與 `config.py` 版本號,僅 recreate `momo-app`,未碰 `momo-db`、未使用 `--remove-orphans``https://mo.wooo.work/health` 回報 V10.91V3 頁面 smoke 與觀測台 production QA 均通過。
- 版本同步至 V10.91。
- 依使用者截圖回饋修正 `/daily_sales`KPI 改為首屏摘要格、日曆密度提升、桌機 1440 與手機 390 均無整頁水平 overflow。
- 依使用者截圖回饋修正 `/edm`:寬螢幕內容最大寬度調整至 1600px、活動表格限制在局部 scroll container、手機版無整頁水平 overflow。
- 新增 `scripts/check_v3_responsive_ui.js`,覆蓋 23 個主要 route 的 desktop/mobile responsive smoke本機通過 46/46。
- 移除 V3 主要頁面 CSS 內殘留負字距,符合新版排版規範。
- 版本同步至 V10.92。
- 正式環境 V10.92 已白名單部署:備份 `/tmp/codex_v3_1092_predeploy_20260512_164549.tgz`,只 recreate `momo-app`,未碰 `momo-db`、未使用 `--remove-orphans`。
- 正式驗證通過:`https://mo.wooo.work/health` 回報 V10.92,觀測台 production QA PASS23 個主要 route 的 desktop/mobile responsive smoke 46/46 PASS。
- 人工視覺 QA 追修 `/growth_analysis` 手機 KPI 可讀性KPI 卡片改為暖墨文字、左側 accent、明確數字層級避免淡底反白造成首屏不可讀。
- 版本同步至 V10.93。
【下次待辦】
- V10.93 白名單部署後補正式 health 與 responsive smoke 結果。
- 為 FastAPI strangler 補 endpoint inventory先列 route owner、資料來源、auth/CSRF/session 需求與 smoke URL再決定第一批可遷移 API。
- `production_v3 3/templates/dashboard.html` 與 `production_v3 3/templates/observability/*` 不得直接覆蓋正式頁;需先補回真實資料功能後才可進入替換候選。
================================================================================
跨平台市場情報模組 (ADR-035 / 2026-05-06) [IN PROGRESS]
================================================================================
【已完成】
- ADR-035定義跨平台市場活動情報系統、feature flags、market_* schema、爬蟲安全邊界與分階段 rollout。
- 模組化盤點:更新 `docs/memory/code_modularization_inventory_20260430.md`,標記市場情報不可塞回 `app.py`、`scheduler.py`、`routes/sales_routes.py` 等大檔。
- Phase 1 安全骨架:新增 `routes/market_intel_routes.py`、`services/market_intel/`、`templates/market_intel/disabled.html`,預設只顯示 disabled 狀態。
- Phase 2 schema 骨架:新增 `database/market_intel_models.py`,定義 `market_platforms`、`market_campaigns`、`market_campaign_snapshots`、`market_campaign_products`、`market_product_price_history`、`market_product_matches`、`market_crawler_runs`。
- Metadata 守門:`database/manager.py` 顯式 import market_intel models`app.py` expected metadata tables 已同步。
- 安全開關:`.env.example` 補 `MARKET_INTEL_ENABLED=false`、`MARKET_INTEL_CRAWLER_ENABLED=false`、`MARKET_INTEL_WRITE_ENABLED=false`。
- Phase 3 read-only adapter 骨架:新增 `services/market_intel/adapters/`,目前註冊 MOMO 與 PChome僅回傳 discovery plan不發 HTTP request、不寫 DB、不掛 scheduler。
- Phase 4 手動 dry-run discovery新增 `services/market_intel/discovery_runner.py` 與 `/api/market_intel/manual_discovery`。預設 `fetch=false` 只回 planned`fetch=true` 也必須在 `MARKET_INTEL_ENABLED` 與 `MARKET_INTEL_CRAWLER_ENABLED` 同時開啟時才允許 HTTP且仍不寫 DB、不掛 scheduler。
- Phase 5 parser 診斷層:新增 `services/market_intel/html_diagnostics.py`,手動 fetch 成功後只萃取 title、page_hash、link count、campaign link candidates不建立正式 campaign/product。
- Phase 6 平台別 scorerMOMO/PChome adapter 提供 URL/text 加權規則diagnostics 同時輸出 generic_score 與 platform_score仍只用於候選排序與人工診斷。
- Phase 7 confidence bandsdiagnostics 將候選標成 `high` / `medium` / `low`,並輸出 `confidence_reason`;只作人工審核提示,不自動建立活動。
- Phase 8 candidate preview API新增 `/api/market_intel/candidate_preview`,把本次 discovery diagnostics 候選合併排序,支援 `min_band` 與 `limit`,只供人工預覽,不入庫。
- Phase 9 UI preview panel`templates/market_intel/disabled.html` 讀取 `/api/market_intel/candidate_preview?fetch=false`,顯示安全空狀態與 flags不做自動外部 fetch。
- Phase 10 platform seed plan新增 `/api/market_intel/platform_seed_plan`,只產生 adapter registry 對應的 `market_platforms` seed rows 與 gate 狀態,不寫 DB。
- Phase 11 Coupang read-only adapter新增 Coupang 酷澎 adapter以官方台灣站與火箭跨境入口作為公開 discovery 起點,預設不發 request、不寫 DB、不掛 scheduler。
- Phase 12 Shopee read-only adapter新增 Shopee 蝦皮 adapter以公開首頁與 Shopee Mall 入口作為 discovery 起點;不得登入、碰會員券、購物車、帳號池或反爬繞過。
- Phase 13 platform seed write guard新增 `/api/market_intel/platform_seed_write_guard`,只回報寫入前 gate 與阻擋原因,預設永遠不寫 DB。
- Phase 14 platform seed writer dry-run新增 `/api/market_intel/schema_smoke` 與 `/api/market_intel/platform_seed_writer_plan`,實際檢查 ORM metadata 並產生 parameterized upsert preview不建立 session、不 commit。
- Phase 15 writer preview panel`templates/market_intel/disabled.html` 讀取 `/api/market_intel/platform_seed_writer_plan`,顯示 schema smoke、upsert preview 與 blocked reasons仍不寫 DB。
- Phase 16 deployment readiness panel新增 `/api/market_intel/deployment_readiness` 與 UI「推版準備檢查」明確回報尚未正式推版、尚未 commit/push、部署 SOP 與 production smoke 尚待人工執行。
- Phase 17 deployment handoff checklist`/api/market_intel/deployment_readiness` 補人工步驟、備援方案、安全部署邊界、production smoke targets 與 `python backup_system.py` 備份要求UI 直接顯示,不執行任何 git/部署/DB 操作;版本同步至 V10.87。
- Phase 18 write approval runbook新增 `/api/market_intel/write_approval_runbook` 與 UI「正式寫入批准檢查」列出 schema smoke、備份、migration review、feature flag、人工批准、rollback 等 gate預設 `ready_for_real_write=false`、`database_session_created=false`、`database_commit_executed=false`;版本同步至 V10.88。
- Phase 19 migration blueprint新增 `/api/market_intel/migration_blueprint` 與 UI「Schema migration 草案」,產生 `migrations/032_market_intel_core_schema.sql` 建議內容、migration apply command shape 與 seed writer command design預設 `file_created=false`、`migration_executed=false`、`database_commit_executed=false`,且 forward SQL 只允許 additive DDL版本同步至 V10.89。
- Phase 20 migration file draft新增本地草稿檔 `migrations/032_market_intel_core_schema.sql`blueprint API 會檢查檔案存在且內容與 blueprint 相符;仍然 `migration_executed=false`、`database_session_created=false`、`database_commit_executed=false`;版本同步至 V10.90。
- Phase 21 seed writer CLI skeleton新增 `scripts/market_intel_seed_writer.py`、`services/market_intel/seed_writer_cli.py` 與 `/api/market_intel/seed_writer_cli_status`CLI 可輸出 seed writer blocked plan但即使帶 `--execute` 與 approval token 也會拒絕真寫入,維持 `database_session_created=false`、`database_commit_executed=false`;版本同步至 V10.94。
- Phase 22 app-only release gate`/api/market_intel/deployment_readiness` 改為區分「安全檢查已可進 app-only 推版」與「API 不執行部署動作」;新增 `mode=app_only_release_gate`、`execution_boundary`,維持 `api_runs_migration=false`、`api_writes_database=false`、`production_deployed=false`;版本同步至 V10.95。
- 正式環境 V10.95 已白名單部署:備份 `/tmp/codex_market_intel_v1095_predeploy_20260512_194041.tgz` 與 compose 備份 `/tmp/docker-compose.market-intel-v1095-mount-20260512_194827.yml`,同步 market_intel runtime 檔案並補 app-only `scripts/`、`migrations/` mount 後僅 recreate `momo-app`,未碰 `momo-db`、未使用 `--remove-orphans``https://mo.wooo.work/health` 回報 V10.95market_intel schema/writer/readiness/migration/seed execute-block smoke 通過。
- Phase 23 seed transaction preview`/api/market_intel/seed_writer_cli_status` 內新增 `transaction_preview`,輸出 `market_platforms` idempotent upsert SQL template、parameter hash、diff 狀態與 runtime orderUI 新增「Seed CLI 交易預覽」panel仍維持 `database_session_created=false`、`transaction_opened=false`、`database_commit_executed=false`;版本同步至 V10.96。
- 正式環境 V10.96 已白名單部署:備份 `/tmp/codex_market_intel_v1096_predeploy_20260512_211619.tgz`,僅同步 market_intel runtime/docs/test 檔案並 recreate `momo-app`,未碰 `momo-db`、未使用 `--remove-orphans``https://mo.wooo.work/health` 回報 V10.96`seed_writer_cli_status` dry-run/execute-block、deployment readiness 與正式頁 UI smoke 均通過。
- Phase 24 read-only DB schema probe新增 `/api/market_intel/schema_db_probe` 與 UI「正式 DB Schema 探針」panel預設 `execute=false` 只回 planned、不連 DB人工 smoke 才可用 `execute=true` 查正式 DB catalog不使用 `DatabaseManager()`、不呼叫 `create_all()`、不建立 ORM session、不寫入、不 commit版本同步至 V10.97。
- 正式環境 V10.97 已白名單部署:備份 `/tmp/codex_market_intel_v1097_predeploy_20260512_214226.tgz`,僅同步 market_intel runtime/docs/test 檔案並 recreate `momo-app`,未碰 `momo-db`、未使用 `--remove-orphans``https://mo.wooo.work/health` 回報 V10.97`schema_db_probe` planned/read-only execute、seed execute-block、deployment readiness 與正式頁 UI smoke 均通過。
- Phase 25 platform seed DB diff probe新增 `/api/market_intel/platform_seed_db_diff` 與 UI「平台 Seed DB 差異探針」panel預設 `execute=false` 只回 planned、不連 DB人工 smoke 才可用明確只讀參數比對 adapter seed 與 `market_platforms` 既有 rows不使用 `DatabaseManager()`、不建立 ORM session、不寫入、不 commit版本同步至 V10.98。
- 正式環境 V10.98 已白名單部署:備份 `/tmp/codex_market_intel_v1098_predeploy_20260512_220309.tgz`,僅同步 market_intel runtime/docs/test 檔案並 recreate `momo-app`,未碰 `momo-db`、未使用 `--remove-orphans``https://mo.wooo.work/health` 回報 V10.98`platform_seed_db_diff` planned/read-only execute、seed execute-block、deployment readiness 與正式頁 UI smoke 均通過;正式 DB 只讀 diff 顯示 `market_platforms` 目前 0 筆,四平台 seed 仍 missing符合未正式寫入狀態。
- Phase 26 platform seed CLI writer`scripts/market_intel_seed_writer.py` 支援 CLI-only 受控寫入,必須同時帶 `--execute`、`--apply-real-write` 與確認 token 才會以 SQLAlchemy Core 短 transaction upsert `market_platforms`API 仍不執行寫入,不建立 ORM session、不連外、不掛 schedulerV10.101 補強 insert 顯式寫入 `created_at` / `updated_at`,避免正式 schema 無 default 時觸發 not-null rollback。
- 正式環境 V10.101 已白名單部署:備份 `/tmp/codex_market_intel_v10100_predeploy_20260513_103809.tgz`、`/tmp/codex_market_intel_v10101_predeploy_20260513_104053.tgz` 與 seed 前快照 `/tmp/codex_market_platforms_v10100_before_20260513_103809.json`;僅 recreate `momo-app`,未碰 `momo-db`、未使用 `--remove-orphans`。CLI seed 首次因 timestamp not-null rollbackV10.101 修正後成功 insert `momo/pchome/coupang/shopee` 四筆 seedread-only diff 顯示 existing=4、missing=0、matching=4正式頁 console error 0。
- 2026-05-13 Codex 只讀複核:`https://mo.wooo.work/health` 回報 V10.111`/api/market_intel/status` 仍為 `enabled=false`、`crawler_enabled=false`、`write_enabled=false`、`dry_run_only=true`、phase 26`/api/market_intel/platform_seed_db_diff?execute=true&platform=all` 只讀確認 `market_platforms` 已有 `momo/pchome/coupang/shopee` 四筆,`existing_seed_count=4`、`missing_codes=[]`、`database_write_executed=false`。
- V10.323 已補正式端 seed writer token-hardening smoke`seed_writer_cli_status` 不回吐 `approval_token_hint`、不洩漏環境 token且明確標示 API 不讀 approval token、不執行 CLI、不寫 DB。
- Phase 27 legacy source bridge preview新增 `services/market_intel/legacy_source_bridge.py` 與 `/api/market_intel/legacy_source_bridge`,只讀盤點既有 `promo_products`、`competitor_prices`、`competitor_price_history`,產生導入 `market_*` 的 mapping / dedupe / blocked operation preview預設 `execute=false` 不連 DB`execute=true` 也只做 read-only query不寫 DB、不建立 ORM session、不連外、不掛 schedulerUI 新增「既有資料橋接預覽」panel版本同步至 V10.182。
- Phase 45 migration live smoke preview新增 `/api/market_intel/migration_live_smoke` 與 UI「正式 DB 只讀 smoke」panel預設 `execute=false` 只回 planned人工 smoke 才可用 `execute=true` 整理 catalog / seed diff 結果,不執行 migration、不寫 DB、不跑 rollback、不掛 scheduler版本同步至 V10.207。
- Phase 46 live DB inventory preview新增 `/api/market_intel/live_db_inventory` 與 UI「正式 DB 庫存總覽」panel預設 `execute=false` 不連 DB人工 smoke 才可用 `execute=true` 對 `market_*` tables 做只讀 count / group by建立平台、活動、商品、比對、告警與 crawler run 基準;版本同步至 V10.209。
- Phase 47 manual sample fetch plan新增 `/api/market_intel/manual_sample_plan` 與 UI「人工樣本 Fetch 計畫」panel預設只輸出平台順序、每平台 1 個公開入口、MCP gate、操作員步驟與備援不抓外站、不寫 DB、不建立 crawler run、不掛 scheduler版本同步至 V10.214。
- Phase 48 manual sample acceptance contract新增 `/api/market_intel/manual_sample_acceptance` 與 UI「樣本結果驗收契約」panel定義 sample result 必要欄位、diagnostics 欄位、驗收門檻、拒收條件、人工決策與升級順序,不載入 sample result、不抓外站、不允許候選導入、不寫 DB版本同步至 V10.215。
- Phase 49 manual sample result review新增 `services/market_intel/manual_sample_review.py`、`/api/market_intel/manual_sample_review` 與 UI「樣本結果審核預覽」panel以純函式評估人工 sample result 是否可進候選預覽,預設不載入結果、不抓外站、不存檔、不寫 DB、不允許候選導入、不掛 scheduler版本同步至 V10.216。
- Phase 50 manual sample review evaluate新增 `/api/market_intel/manual_sample_review/evaluate` POST 與 UI JSON 審核入口,允許操作員貼入單筆 sample result 即時回傳 PASS/BLOCK不保存 payload、不回吐完整 HTML、不寫 DB、不建立候選活動、不允許候選導入、不掛 scheduler版本同步至 V10.219。
- V10.220 補 Phase 50 UI POST CSRF header`manual_sample_review/evaluate` 保持 CSRF 保護,頁面 fetch 送出 `X-CSRFToken`,不豁免安全檢查。
- Phase 51 manual sample candidate handoff新增 `/api/market_intel/manual_sample_review/candidate_handoff` POST 與 UI handoff 按鈕,將已通過審核的 sample result 轉成只讀候選活動 preview payload不保存 handoff、不建立 review queue、不寫 market_*、不允許候選導入、不掛 scheduler版本同步至 V10.222。
- Phase 52 manual sample candidate queue draft新增 `services/market_intel/manual_sample_candidate_queue.py`、`/api/market_intel/manual_sample_review/candidate_queue_draft` POST 與 UI queue 草案按鈕,將 handoff 候選轉成只讀人工審核 queue draft不建立正式 queue、不保存草案、不寫 market_*、不自動核准候選、不掛 scheduler版本同步至 V10.223。
- V10.224 補 PPT 報表覆蓋矩陣:`/observability/ppt_audit_history` 將每個定義簡報同列串起 DB 寫入、線上預覽、視覺 QA 與交付狀態,並提供預覽、預熱、重跑操作,避免只顯示「目標已產生」。
- Phase 53 manual sample candidate queue approval新增 `/api/market_intel/manual_sample_review/candidate_queue_approval` POST 與 UI 送審 gate 按鈕,將 queue draft row preview 對齊既有 `market_alert_review_queue` 契約,檢查必填欄位、寫入 flags、備份與人工批准 gate不建立 approval record、不寫 review queue、不開 DB transaction、不掛 scheduler版本同步至 V10.225。
- V10.226 補 PPT 視覺 QA runtime checklist`/observability/ppt_audit_history` 在視覺模型未就緒時顯示 Feature Flag、LibreOffice、Vision Model 三段檢查與下一步操作,避免只看到「停用」而不知道卡在哪。
- Phase 54 manual sample candidate queue transaction新增 `/api/market_intel/manual_sample_review/candidate_queue_transaction` POST 與 UI transaction preview 按鈕,將 queue row preview 轉成 `market_alert_review_queue` idempotent insert statement、payload hash 與 rollback plan不開 DB connection、不開 transaction、不 commit、不建立 approval record版本同步至 V10.227。
- V10.228 補 PPT 視覺 QA 背景狀態卡:新增 `/observability/ppt_audit/vision_status` 與頁面 Vision QA 狀態卡,讓立即視覺 QA 排入後可看 queued/running/completed/error 與最近審核摘要,不必刷新猜測。
- V10.229 修正 PPT 視覺 QA 多 worker 狀態漂移:將 queued/running/completed/error 寫入 `/app/data/ppt_vision_audit_status.json` runtime state所有 Gunicorn worker 共用同一份狀態並阻擋重複排入。
- Phase 55 candidate queue writer CLI gate新增 `/api/market_intel/manual_sample_review/candidate_queue_writer_status` POST、`scripts/market_intel_candidate_queue_writer.py` 與 UI writer gate 按鈕,定義 `MARKET_INTEL_QUEUE_WRITE_APPROVAL` 一次性 token、execute/apply flags、備份、migration smoke 與 rollback gate本階段仍不開 DB connection、不寫 `market_alert_review_queue`、不 commit、不掛 scheduler版本同步至 V10.230。
- Phase 56 candidate queue writer preflight新增 `/api/market_intel/manual_sample_review/candidate_queue_writer_preflight` POST 與 `services/market_intel/candidate_queue_writer_preflight.py`,檢查 transaction payload key 到 `market_alert_review_queue` 欄位映射、缺欄與 dedupe unique index頁面預設 execute=false 不連 DBCLI 可明確 `--read-only-preflight` 只讀 catalog版本同步至 V10.232。
- Phase 57 candidate queue writer CLI transaction`scripts/market_intel_candidate_queue_writer.py` 在 CLI-only 情境支援受控 transaction必須同時通過 transaction payload、read-only preflight、`--execute`、`--apply-real-write`、一次性 token、備份確認與 migration live smoke 才會以 SQLAlchemy Core idempotent insert `market_alert_review_queue`API/UI 仍不傳 token、不連 DB、不寫 queue、不掛 scheduler版本同步至 V10.234。
- V10.235 補 PPT 視覺 QA stale recovery背景狀態寫入 worker PID若部署 reload 後舊 PID 已不存在,`/observability/ppt_audit/vision_status` 會自動把 running 轉為可診斷 error 並允許重新排入,避免人工清 runtime state。
- Phase 58 candidate queue writer post-write smoke新增 `services/market_intel/candidate_queue_writer_postwrite_smoke.py`、POST `/api/market_intel/manual_sample_review/candidate_queue_writer_postwrite_smoke` 與 UI smoke 按鈕,依 transaction preview 的 dedupe key 只讀查詢 `market_alert_review_queue`,讓 CLI 真寫入後可驗證 row 是否存在;頁面預設 execute=false 不連 DB、不寫 queue、不 commit、不掛 scheduler版本同步至 V10.236。
- Phase 59 candidate queue writer operator drill新增 `services/market_intel/candidate_queue_writer_operator_drill.py`、POST `/api/market_intel/manual_sample_review/candidate_queue_writer_operator_drill` 與 UI drill 按鈕,組裝 reviewed sample、備份、read-only preflight、CLI writer、post-write smoke 的操作員順序API/UI 不讀 approval token、不執行 CLI、不連 DB、不寫 queue、不 commit、不掛 scheduler版本同步至 V10.237。
- V10.238 補業績圖表 runtime QA 與分析 tabs 窄版修正:新增 `quick_review --sales-charts` 檢查 `/daily_sales`、`/growth_analysis` 的 Chart.js ready、可繪製資料集與 canvas 非空白;同時把分析報表 tabs 手機版改為自適應 grid避免 Metabase/Grist 外部連結超出右側。
- Phase 60 candidate queue writer run package新增 `services/market_intel/candidate_queue_writer_run_package.py`、POST `/api/market_intel/manual_sample_review/candidate_queue_writer_run_package` 與 UI run package 按鈕,整理正式 CLI 小流量寫入前的 payload manifest、required artifacts、command bundle、operator signoff 與 rollback planAPI/UI 不產檔、不讀 approval token、不執行 CLI、不連 DB、不寫 queue、不 commit、不掛 scheduler版本同步至 V10.240。
- Phase 61 candidate queue writer run readiness新增 `services/market_intel/candidate_queue_writer_run_readiness.py`、POST `/api/market_intel/manual_sample_review/candidate_queue_writer_run_readiness` 與 UI readiness 按鈕,檢查 reviewed sample 檔案路徑、備份路徑、preflight 輸出、migration live smoke、shell-only token acknowledgement 與禁止 token 進 APIAPI/UI 不產檔、不讀 approval token、不執行 CLI、不連 DB、不寫 queue、不 commit、不掛 scheduler版本同步至 V10.245。
- Phase 62 candidate queue writer run receipt新增 `services/market_intel/candidate_queue_writer_run_receipt.py`、POST `/api/market_intel/manual_sample_review/candidate_queue_writer_run_receipt` 與 UI receipt 按鈕,審核 CLI 寫入後的 writer output、post-write smoke、dedupe key 一致性與 artifact 路徑API/UI 不回吐 receipt 原文、不讀 approval token、不執行 CLI、不連 DB、不寫 queue、不掛 scheduler版本同步至 V10.247。
- Phase 63 candidate queue writer run closeout新增 `services/market_intel/candidate_queue_writer_run_closeout.py`、POST `/api/market_intel/manual_sample_review/candidate_queue_writer_run_closeout` 與 UI closeout 按鈕,在 receipt 通過後檢查 closeout artifact、操作員人工 queue review/read-only inventory 確認與安全 promotion gateAPI/UI 不回吐原始 receipt、不讀 approval token、不執行 CLI、不連 DB、不寫 queue、不掛 scheduler版本同步至 V10.248。
- Phase 64 candidate queue review handoff新增 `services/market_intel/candidate_queue_review_handoff.py`、POST `/api/market_intel/manual_sample_review/candidate_queue_review_handoff` 與 UI handoff 按鈕,將 writer closeout 轉成人工 queue review / read-only inventory 交接契約API/UI 不讀 approval token、不查 DB、不更新 review_state、不補寫 queue、不掛 scheduler版本同步至 V10.251。
- Phase 65 candidate queue review inventory新增 `services/market_intel/candidate_queue_review_inventory.py`、`routes/market_intel_review_routes.py`、POST `/api/market_intel/manual_sample_review/candidate_queue_review_inventory` 與 UI inventory 按鈕,把 handoff、post-write smoke、live DB inventory 合併成只讀人工審核庫存檢查;預設不連 DB人工只讀查詢仍不更新 review_state、不補寫 queue、不讀 token、不掛 scheduler版本同步至 V10.252。
- Phase 66 candidate queue review decision新增 `services/market_intel/candidate_queue_review_decision.py`、POST `/api/market_intel/manual_sample_review/candidate_queue_review_decision` 與 UI decision 按鈕,將通過 inventory 的 queue row 整理成人工決策草案API/UI 不更新 review_state、不寫 decision record、不讀 token、不掛 scheduler版本同步至 V10.254。
- Phase 67 candidate queue review decision approval新增 `services/market_intel/candidate_queue_review_decision_approval.py`、POST `/api/market_intel/manual_sample_review/candidate_queue_review_decision_approval` 與 UI approval gate 按鈕,檢查人工決策草案是否可進入下一個 CLI-only transaction previewAPI/UI 不更新 review_state、不寫 decision record、不建立 approval record、不讀 token、不掛 scheduler版本同步至 V10.255。
- Phase 68 candidate queue review decision transaction新增 `services/market_intel/candidate_queue_review_decision_transaction.py`、POST `/api/market_intel/manual_sample_review/candidate_queue_review_decision_transaction` 與 UI transaction preview 按鈕,將 approval update preview 轉成 `review_state` update statement、payload hash 與 rollback planAPI/UI 不更新 review_state、不開 DB connection、不執行 CLI、不讀 token、不掛 scheduler版本同步至 V10.256。
- Phase 69 candidate queue review decision writer CLI gate新增 `services/market_intel/candidate_queue_review_decision_writer_cli.py`、`scripts/market_intel_review_decision_writer.py`、POST `/api/market_intel/manual_sample_review/candidate_queue_review_decision_writer_status` 與 UI writer gate 按鈕,先建立 shell-only review_state writer gate 與 command bundlewriter implementation 本階段保持 disabledAPI/UI 不讀 token、不執行 CLI、不連 DB、不更新 review_state、不掛 scheduler版本同步至 V10.257。
- Phase 70 candidate queue review decision writer preflight新增 `services/market_intel/candidate_queue_review_decision_writer_preflight.py`、POST `/api/market_intel/manual_sample_review/candidate_queue_review_decision_writer_preflight` 與 UI preflight 按鈕,檢查 writer status、review_state update payload、狀態轉換與禁止 token 進 APIAPI/UI 即使收到 execute/apply_real_write 也不連 DB、不執行 CLI、不更新 review_state、不 commit、不讀 token、不掛 scheduler版本同步至 V10.258。
- V10.259 補 Phase 70 preflight 合約與 OCLearn queue 時區preflight 補 planned/read-only catalog probe 欄位、dedupe unique index 檢查與 route 重複註冊清理OCLearn embedding queue 的 created_at/updated_at/stale cutoff 改為台北 naive避免 UTC/台北時間差讓 processing 任務卡住。
- Phase 71 candidate queue review decision writer post-write smoke新增 `services/market_intel/candidate_queue_review_decision_writer_postwrite_smoke.py`、POST `/api/market_intel/manual_sample_review/candidate_queue_review_decision_writer_postwrite_smoke` 與 UI smoke 按鈕,人工 CLI 更新 review_state 後可用 dedupe key 只讀驗證 row 是否存在且 state 符合預期API/UI 預設不連 DBexecute=true 也只讀查詢,不更新 review_state、不 commit、不讀 token、不掛 scheduler版本同步至 V10.260。
- Phase 72 candidate queue review decision writer operator drill新增 `services/market_intel/candidate_queue_review_decision_writer_operator_drill.py`、POST `/api/market_intel/manual_sample_review/candidate_queue_review_decision_writer_operator_drill` 與 UI drill 按鈕,將 review_state CLI 更新前後的 transaction JSON、備份、preflight、CLI writer、post-write smoke 與 rollback plan 組成可稽核操作順序API/UI 不讀 token、不執行 CLI、不連 DB、不更新 review_state、不 commit、不掛 scheduler版本同步至 V10.261。
- Phase 73 candidate queue review decision writer run package新增 `services/market_intel/candidate_queue_review_decision_writer_run_package.py`、POST `/api/market_intel/manual_sample_review/candidate_queue_review_decision_writer_run_package` 與 UI package 按鈕,將 review_state transaction、preflight、operator drill、writer gate、post-write smoke、必要 artifact 與 rollback plan 組成正式 CLI 更新前的可稽核 run packageAPI/UI 不寫檔、不讀 token、不執行 CLI、不連 DB、不更新 review_state、不 commit、不掛 scheduler版本同步至 V10.262。
- Phase 74 candidate queue review decision writer run readiness新增 `services/market_intel/candidate_queue_review_decision_writer_run_readiness.py`、POST `/api/market_intel/manual_sample_review/candidate_queue_review_decision_writer_run_readiness` 與 UI readiness 按鈕,檢查 review_state CLI 更新前的 transaction JSON、備份、preflight、shell-only token 與 post-write smoke 計畫是否齊備API/UI 不寫檔、不讀 token、不執行 CLI、不連 DB、不更新 review_state、不 commit、不掛 scheduler版本同步至 V10.264。
- Phase 75 candidate queue review decision writer run receipt新增 `services/market_intel/candidate_queue_review_decision_writer_run_receipt.py`、POST `/api/market_intel/manual_sample_review/candidate_queue_review_decision_writer_run_receipt` 與 UI receipt 按鈕,審核 review_state CLI 更新後的 writer output、post-write smoke、dedupe key 一致性、artifact 路徑與 token 外洩風險API/UI 不回吐 receipt 原文、不讀 token、不執行 CLI、不連 DB、不更新 review_state、不 commit、不掛 scheduler版本同步至 V10.266。
- Phase 76 candidate queue review decision writer run closeout新增 `services/market_intel/candidate_queue_review_decision_writer_run_closeout.py`、POST `/api/market_intel/manual_sample_review/candidate_queue_review_decision_writer_run_closeout` 與 UI closeout 按鈕,在 review_state receipt 通過後整理 closeout gate、操作員 closeout artifact、post-closeout read-only inventory 確認與 promotion 摘要API/UI 不回吐 receipt 原文、不讀 token、不執行 CLI、不連 DB、不更新 review_state、不 commit、不掛 scheduler版本同步至 V10.268。
- Phase 77 candidate queue review decision post-closeout inventory新增 `services/market_intel/candidate_queue_review_decision_post_closeout_inventory.py`、`routes/market_intel_review_post_routes.py`、POST `/api/market_intel/manual_sample_review/candidate_queue_review_decision_post_closeout_inventory` 與 UI inventory 按鈕,在 review_state closeout 後整理 post-write smoke、live inventory、dedupe key 與 review_state 結果API/UI 不讀 token、不執行 CLI、不更新 review_state、不寫 DB、不 commit、不掛 scheduler版本同步至 V10.270。
- Phase 78 candidate queue review completion archive新增 `services/market_intel/candidate_queue_review_completion_archive.py`、POST `/api/market_intel/manual_sample_review/candidate_queue_review_completion_archive` 與 UI archive 按鈕,在 post-closeout inventory 通過後整理 receipt、closeout、inventory、dedupe key、review_state row snapshot 與 artifact path manifestAPI/UI 不寫檔、不讀 token、不執行 CLI、不更新 review_state、不寫 DB、不 commit、不掛 scheduler版本同步至 V10.273。
- Phase 79 candidate queue review archive summary新增 `services/market_intel/candidate_queue_review_archive_summary.py`、POST `/api/market_intel/manual_sample_review/candidate_queue_review_archive_summary` 與 UI summary 按鈕,在 review completion archive 後整理可供摘要/報表審核的結構化輸入API/UI 不呼叫 LLM、不派送 Telegram、不寫檔、不讀 token、不執行 CLI、不更新 review_state、不寫 DB、不 commit、不掛 scheduler版本同步至 V10.276。
- Phase 80 candidate queue review AI summary preflight新增 `services/market_intel/candidate_queue_review_ai_summary_preflight.py`、POST `/api/market_intel/manual_sample_review/candidate_queue_review_ai_summary_preflight` 與 UI preflight 按鈕,在 archive summary 後檢查 Ollama-first 三主機級聯與 Gemini 備援邊界API/UI 不呼叫 LLM、不派送 Telegram、不寫檔、不讀 token、不執行 CLI、不更新 review_state、不寫 DB、不 commit、不掛 scheduler版本同步至 V10.278。
- Phase 81 candidate queue review AI summary run package新增 `services/market_intel/candidate_queue_review_ai_summary_run_package.py`、POST `/api/market_intel/manual_sample_review/candidate_queue_review_ai_summary_run_package` 與 UI package 按鈕,在 AI summary preflight 後整理手動 Ollama 摘要任務包、prompt contract 與輸出 schemaAPI/UI 不呼叫 LLM、不派送 Telegram、不寫 run package、不讀 token、不執行 CLI、不更新 review_state、不寫 DB、不 commit、不掛 scheduler版本同步至 V10.280。
- Phase 82 candidate queue review AI summary output receipt新增 `services/market_intel/candidate_queue_review_ai_summary_output_receipt.py`、POST `/api/market_intel/manual_sample_review/candidate_queue_review_ai_summary_output_receipt` 與 UI receipt 按鈕,在 run package 後驗收人工 Ollama 摘要輸出的 schema、evidence_refs 與 model_routeAPI/UI 不呼叫 LLM、不派送 Telegram、不寫 receipt、不讀 token、不執行 CLI、不更新 review_state、不寫 DB、不 commit、不掛 scheduler版本同步至 V10.285。
- Phase 83 candidate queue review AI summary persistence preflight新增 `services/market_intel/candidate_queue_review_ai_summary_persistence_preflight.py`、POST `/api/market_intel/manual_sample_review/candidate_queue_review_ai_summary_persistence_preflight` 與 UI preflight 按鈕,在 output receipt 後整理 future CLI-only `market_alert_review_queue.metadata_json.ai_summary_review` persistence contract、payload hash 與 metadata patch previewAPI/UI 不呼叫 LLM、不派送 Telegram、不寫 preflight、不寫 summary record、不寫 metadata_json、不讀 token、不執行 CLI、不更新 review_state、不寫 DB、不 commit、不掛 scheduler版本同步至 V10.286。
- Phase 84 candidate queue review AI summary persistence transaction新增 `services/market_intel/candidate_queue_review_ai_summary_persistence_transaction.py`、POST `/api/market_intel/manual_sample_review/candidate_queue_review_ai_summary_persistence_transaction` 與 UI transaction 按鈕,在 persistence preflight 後產生 future CLI-only `metadata_json` UPDATE statement preview、parameter preview 與 rollback planAPI/UI 不開 DB、不執行 SQL、不寫 transaction、不寫 summary record、不寫 metadata_json、不讀 token、不執行 CLI、不更新 review_state、不派送 Telegram、不呼叫 LLM、不 commit、不掛 scheduler版本同步至 V10.287。
- Phase 85 candidate queue review AI summary persistence writer preflight新增 `services/market_intel/candidate_queue_review_ai_summary_persistence_writer_preflight.py`、POST `/api/market_intel/manual_sample_review/candidate_queue_review_ai_summary_persistence_writer_preflight` 與 UI writer preflight 按鈕,在 transaction preview 後檢查 CLI-only writer contract、metadata_json backup requirement、post-write smoke requirement 與 artifact path gateAPI/UI 不開 DB、不執行 SQL、不寫 preflight、不寫 summary record、不寫 metadata_json、不讀 token、不執行 CLI、不更新 review_state、不派送 Telegram、不呼叫 LLM、不 commit、不掛 scheduler版本同步至 V10.290。
- Phase 86 candidate queue review AI summary persistence run package新增 `services/market_intel/candidate_queue_review_ai_summary_persistence_run_package.py`、POST `/api/market_intel/manual_sample_review/candidate_queue_review_ai_summary_persistence_run_package` 與 UI run package 按鈕,在 writer preflight 後整理 payload manifest、CLI command bundle、required artifacts、operator signoff 與 rollback planAPI/UI 不開 DB、不執行 SQL、不寫 run package、不寫 summary record、不寫 metadata_json、不讀 token、不執行 CLI、不更新 review_state、不派送 Telegram、不呼叫 LLM、不 commit、不掛 scheduler版本同步至 V10.294。
- Phase 87 candidate queue review AI summary persistence run readiness新增 `services/market_intel/candidate_queue_review_ai_summary_persistence_run_readiness.py`、POST `/api/market_intel/manual_sample_review/candidate_queue_review_ai_summary_persistence_run_readiness` 與 UI readiness 按鈕,在 run package 後檢查 artifact path、metadata_json backup、read-only preflight、shell-only token 與 post-write smoke 計畫API/UI 不開 DB、不執行 SQL、不寫 readiness artifact、不寫 metadata_json、不讀 token、不執行 CLI、不更新 review_state、不派送 Telegram、不呼叫 LLM、不 commit、不掛 scheduler版本同步至 V10.297。
- V10.248 補市場情報 390px preview panel QAsample review 工具列改為 textarea + 可換行 action rail移除舊的硬編 8 欄 grid`check_responsive_overflow` 新增 `--screenshot-all`,本機 390x844 `/market_intel` 真頁面 QA 通過且 overflow=0。
- V10.250 補 Code Review Gemini 備援遙測護欄Ollama 主路徑失敗時 `fallback_to` 明確指向 `code_review_openclaw_gemini`測試鎖住「Gemini 不得記成 `code_review_openclaw` 主 caller」AI Calls 觀測台會把 legacy `code_review_openclaw + gemini` 顯示成 Gemini 備援,避免誤判 Gemini-first。
- Schema smoke`tests/test_market_intel_skeleton.py` 檢查 `Base.metadata` 內含 ADR-035 八張 `market_*` tables。
- Desktop UI QA本機只註冊 `market_intel_bp` 的 Flask harness 載入 `/market_intel`,確認 Phase 15、候選預覽、writer preview、安全 flags、點陣暖紙視覺正常console error 0。
- API QA`/api/market_intel/schema_smoke` 通過 7 張表與 `market_platforms` 必要欄位檢查;`/api/market_intel/platform_seed_writer_plan` 回傳 4 筆 dry-run upsert preview`writes_executed=false`,四平台皆 `blocked_dry_run_only`。
- Narrow viewport UI QAin-app browser 窄版畫面確認側欄收合、卡片不水平爆版、候選狀態顯示 `momo/pchome/coupang/shopee:planned`。
- 測試:新增 `tests/test_market_intel_skeleton.py`,確認預設 flags 全關、adapter 不允許 network/write/scheduler手動 discovery / candidate preview 預設不發 requestparser/scorer/confidence 診斷只輸出 JSONUI 只使用 `fetch=false`platform seed plan 只讀且需 gate。
【下次待辦】
- 下次市場情報 seed writer 只需保留定期 smoke確認 `approval_token_hint` 不回歸且 `api_reads_approval_token=false`、`api_executes_cli=false`、`api_writes_database=false`。
- 正式推版前需實際執行 worktree scope review、`python backup_system.py`、commit/push 目標變更、讀 deployment SOP 與 ADR-011且只跑 `/health` 與市場情報頁 smoke。
- 下一步才可在明確批准且具備真實 reviewed sample JSON 後做正式 DB 的 queue writer CLI 小流量 operator run先用 run readiness、run package、operator drill、post-write smoke、run receipt、run closeout 與 queue review handoff 做順序與只讀驗證,預設 API/UI 不得寫 DB也不得執行 migration。
- 市場情報 UI 後續頁面必須沿用 V2 暖紙、暖墨、等寬數字與點陣風格,禁止複製巨型分析頁 template 模式。
================================================================================
AI 自動化閉環治理同步 (2026-04-29) [DONE]
================================================================================
@@ -694,8 +1077,8 @@ gcloud compute ssh momo-server --zone=asia-east1-a \
24. [CRITICAL] 移除硬編碼敏感資訊:
- 檔案: config.py (第 17, 22, 26, 35, 40, 173 行)
- 問題: 所有 API 金鑰、密碼、Token 直接寫在程式碼中
• LOGIN_PASSWORD = "0936223270"
• TELEGRAM_BOT_TOKEN = "8075645931:AAH-EGKMo8ZC4QJs-Nc1_0s92xHrGdQvdpg"
• LOGIN_PASSWORD = "<LOGIN_PASSWORD>"
• TELEGRAM_BOT_TOKEN = "<TELEGRAM_BOT_TOKEN>"
• LINE_CHANNEL_ACCESS_TOKEN = "nD6MSXjB2FyB111zpT6Yik5B275mi6olHjjf94VnqN..."
• EMAIL_HOST_PASSWORD = "jopokbhdpnnborjd"
• NGROK_AUTH_TOKEN = "36e27NM5V7sUJ8QxJIAAWCp7sUv_3brtcrBarYvcP3SbvFKhF"
@@ -892,3 +1275,15 @@ gcloud compute ssh momo-server --zone=asia-east1-a \
* Top 3 商業洞察卡片。
* 點擊卡片後的詳細列表 (Modal)。
* 詳細列表的 Excel 匯出。
================================================================================
【V10.490 OpenClaw 舊策略 Action 相容修補】
================================================================================
2026-05-31:
- 正式日誌觀察到 ElephantAlpha 執行器收到 `agent=openclaw action=generate_market_strategy` 時,被誤判為未知步驟。
- 本次修補將 `generate_market_strategy` 納入既有 OpenClaw advisory no-op 清單,與 `generate_resource_optimization_strategy` 一致:
* 只記錄 skipped warning
* 不觸發 circuit breaker
* 不執行外部策略動作
* 不變更任何價格或正式候選資料
- 已補測試:舊策略 action 可安全跳過,未知 action 仍維持 fail-fast。

View File

@@ -1,200 +1,16 @@
# WOOO AIOps Core
智慧雲端運維平台核心模組
> Historical stub only. Do not install dependencies or deploy services from this
> directory.
## 架構概覽
This directory originally sketched a standalone AIOps SaaS module, but the
actual production implementation now lives in the main momo-pro-system codebase:
```
aiops-core/
├── deploy_engine/ # 部署引擎
│ ├── deploy_service.py # 主部署服務
│ ├── template_renderer.py # Jinja2 模板渲染
│ └── k8s_client.py # Kubernetes 客戶端
├── monitor_engine/ # 監控引擎
│ ├── monitor_service.py # 監控服務
│ ├── prometheus_client.py # Prometheus API
│ └── alert_manager.py # Alertmanager API
├── repair_engine/ # 自動修復引擎
│ ├── repair_service.py # 修復決策引擎
│ ├── repair_executor.py # 修復執行器
│ └── repair_strategies.py # 修復策略
├── templates/ # K8s 部署模板
│ ├── base/ # 基礎模板
│ │ ├── namespace.yaml.j2
│ │ ├── service.yaml.j2
│ │ └── ingress.yaml.j2
│ └── frameworks/ # 框架專用模板
│ ├── fastapi/
│ ├── flask/
│ ├── express/
│ └── nextjs/
├── api/ # FastAPI 後端
│ ├── main.py # 應用入口
│ └── routers/ # API 路由
│ ├── auth.py # 認證
│ ├── apps.py # 應用管理
│ ├── deployments.py # 部署管理
│ ├── monitoring.py # 監控
│ ├── repairs.py # 自動修復
│ └── users.py # 用戶管理
└── web/ # React 前端
├── src/
│ ├── pages/ # 頁面
│ ├── components/ # 組件
│ └── lib/ # 工具庫
└── package.json
```
- Current AutoHeal service: `services/auto_heal_service.py`
- Current Aider heal executor: `services/aider_heal_executor.py`
- Architecture decision: `docs/adr/ADR-013-aiops-autoheal.md`
- Full-auto code-heal decision: `docs/adr/ADR-020-code-review-full-autoheal.md`
## 核心功能
### 1. Deploy Engine - 一鍵部署
```python
from aiops_core.deploy_engine import DeployService
deploy_service = DeployService()
# 部署新應用
result = deploy_service.deploy(
app=AppConfig(
name="my-api",
framework="fastapi",
git_repo="https://github.com/user/repo.git",
branch="main"
)
)
```
### 2. Monitor Engine - 智能監控
```python
from aiops_core.monitor_engine import MonitorService
monitor_service = MonitorService()
# 設置監控
monitor_service.setup_monitoring(
config=MonitorConfig(
app_name="my-api",
namespace="default",
telegram_chat_id="123456789"
)
)
# 取得健康狀態
health = monitor_service.get_app_health("my-api", "default")
```
### 3. Repair Engine - 自動修復
```python
from aiops_core.repair_engine import RepairService
repair_service = RepairService()
# 處理告警,自動決定並執行修復
repair_service.process_alert({
"labels": {
"alertname": "HighMemoryUsage",
"app": "my-api",
"namespace": "default"
}
})
```
## 支援的框架
| 框架 | 狀態 | 預設端口 |
|------|------|---------|
| FastAPI | ✅ | 8000 |
| Flask | ✅ | 5000 |
| Express.js | ✅ | 3000 |
| Next.js | ✅ | 3000 |
| Django | 🚧 | 8000 |
| NestJS | 🚧 | 3000 |
## 自動修復策略
| 告警類型 | 修復動作 |
|---------|---------|
| AppDown | 重啟 Pod |
| HighMemoryUsage | 重啟 Pod |
| PodOOMKilled | 增加記憶體限制 +50% |
| HighCPUUsage | 擴容 +50% |
| HighHTTP5xxRate | 回滾到上一版本 |
| PostgresHighConnections | VACUUM ANALYZE |
| DiskSpaceLow | 清理快取 |
## API 端點
### 認證
- `POST /api/auth/login` - 登入
- `POST /api/auth/register` - 註冊
- `GET /api/auth/me` - 取得當前用戶
### 應用管理
- `GET /api/apps` - 列出應用
- `POST /api/apps` - 創建應用
- `GET /api/apps/{id}` - 取得應用詳情
- `PUT /api/apps/{id}` - 更新應用
- `DELETE /api/apps/{id}` - 刪除應用
- `POST /api/apps/{id}/start` - 啟動應用
- `POST /api/apps/{id}/stop` - 停止應用
- `POST /api/apps/{id}/restart` - 重啟應用
### 部署
- `GET /api/deployments` - 列出部署記錄
- `POST /api/deployments` - 創建部署
- `POST /api/deployments/{id}/cancel` - 取消部署
- `POST /api/deployments/{id}/rollback` - 回滾部署
### 監控
- `GET /api/monitoring/dashboard` - 儀表板概覽
- `GET /api/monitoring/apps/{id}/metrics` - 應用指標
- `GET /api/monitoring/apps/{id}/health` - 健康狀態
- `GET /api/monitoring/alerts` - 告警列表
### 自動修復
- `GET /api/repairs` - 修復記錄
- `GET /api/repairs/stats` - 修復統計
- `POST /api/repairs/apps/{id}/trigger` - 手動觸發修復
## 快速開始
### 啟動 API 服務
```bash
cd aiops-core/api
pip install -r requirements.txt
uvicorn main:app --reload --port 8000
```
### 啟動 Web 前端
```bash
cd aiops-core/web
npm install
npm run dev
```
## 環境變數
```bash
# API
JWT_SECRET=your-secret-key
PROMETHEUS_URL=http://prometheus:9090
ALERTMANAGER_URL=http://alertmanager:9093
TELEGRAM_BOT_TOKEN=your-bot-token
# Web
NEXT_PUBLIC_API_URL=http://localhost:8000/api
```
## 授權
© 2026 WOOO TECH. All rights reserved.
The previous `aiops-core/requirements.txt` listed dependencies for non-existent
FastAPI, React, Kubernetes, Redis, and Celery modules. It was removed to avoid
dependency drift and accidental installation in CI or local setup scripts.

View File

@@ -1,56 +0,0 @@
# =============================================================================
# WOOO AIOps - Python Dependencies
# =============================================================================
# Web Framework
fastapi>=0.109.0
uvicorn[standard]>=0.27.0
python-multipart>=0.0.6
# Database
sqlalchemy>=2.0.0
psycopg2-binary>=2.9.9
alembic>=1.13.0
# Authentication
pyjwt>=2.8.0
passlib[bcrypt]>=1.7.4
# Template Rendering
jinja2>=3.1.2
pyyaml>=6.0.1
# HTTP Client
requests>=2.31.0
httpx>=0.26.0
# Kubernetes
kubernetes>=29.0.0
# Monitoring & Alerting
prometheus-client>=0.19.0
# Caching
redis>=5.0.0
# Task Queue (可選)
celery>=5.3.0
# Utilities
python-dotenv>=1.0.0
pydantic>=2.5.0
pydantic-settings>=2.1.0
# Logging
structlog>=24.1.0
# Testing
pytest>=7.4.0
pytest-asyncio>=0.23.0
httpx>=0.26.0
# Security
cryptography>=41.0.0
# Date/Time
python-dateutil>=2.8.2

98
app.py
View File

@@ -1,22 +1,10 @@
# ================= TODO LIST (待辦事項 - 重開機後請依序執行) =================
# 1. [驗證] 重啟 app.py 後,重新匯入 Excel確認「自動去重」功能是否生效 (重複匯入應顯示 0 筆新增)。
# 2. [檢查] 前往 /sales_analysis 頁面,確認 '狀態' 欄位是否正確顯示 'F' (目前為原始匯入模式)。
# 3. [決策] 若資料顯示正常,評估是否需要恢復「智慧資料清理」邏輯 (目前程式碼第 1160 行左右已註解)。
# 4. [備份] 確認系統運作正常後,執行系統備份。
# =======================================================================
import os
import sys
import time
import threading
import math
import json
import hashlib
import shutil
import zipfile
import re
import io # V-New: 用於 Excel 匯出
import traceback # V-Fix: 用於錯誤追蹤
from datetime import datetime, timedelta, timezone
# ================= 🔧 1. 環境與路徑鎖定 =================
@@ -41,7 +29,7 @@ except OSError as e:
# ================= 🔧 2. 核心模組導入 =================
try:
from flask import Flask, render_template, jsonify, request, send_file, redirect, url_for, send_from_directory, flash, session
from flask import Flask, render_template, jsonify, request, send_file, redirect, url_for, flash, session
from werkzeug.utils import secure_filename
from pyngrok import ngrok, conf
import schedule
@@ -70,7 +58,16 @@ except ImportError as e:
# ================= 🔧 3. 系統核心配置 =================
# 從 config.py 匯入必要的設定
from config import EXCEL_EXPORT_DIR, DATABASE_TYPE, validate_critical_config
from config import (
SYSTEM_VERSION,
WEBCRUMBS_BASE_URL,
WEBCRUMBS_ENABLED,
WEBCRUMBS_ASSET_UPSTREAM_URL,
WEBCRUMBS_PLUGIN_BASE_URL,
WEBCRUMBS_RUNTIME_URL,
WEBCRUMBS_RUNTIME_VERSION,
validate_critical_config,
)
sys_log = SystemLogger("Web_Server").get_logger()
@@ -96,7 +93,14 @@ except Exception as e:
# 🚩 系統版本定義 (備份與顯示用)
# 🚩 2026-05-01 V10.76: Move monthly analysis report onto V2 shell
SYSTEM_VERSION = "V10.77"
# 🚩 2026-05-07 V10.90: Market intelligence migration file draft
# 🚩 2026-05-12 V10.92: Frontend V3 responsive QA + daily_sales/edm fixes
# 🚩 2026-05-12 V10.93: Growth analysis mobile KPI readability polish
# 🚩 2026-05-12 V10.94: Market intelligence seed writer CLI skeleton
# 🚩 2026-05-12 V10.96: Market intelligence seed transaction preview
# 🚩 2026-05-12 V10.97: Market intelligence read-only DB schema probe
# 🚩 2026-05-12 V10.98: Market intelligence platform seed DB diff probe
# SYSTEM_VERSION 單一來源於 config.py。
# ==========================================
# 🔒 SQL Injection 防護函數
@@ -134,13 +138,22 @@ else:
TEMPLATE_DIR = os.path.join(BASE_DIR, 'templates')
STATIC_DIR = os.path.join(BASE_DIR, 'web/static')
# 檢查關鍵模板是否存在
if not os.path.exists(os.path.join(TEMPLATE_DIR, 'dashboard.html')):
sys_log.warning(f"[Web] [Template] ⚠️ 警告: 找不到 dashboard.html | Path: {TEMPLATE_DIR}")
# 檢查關鍵模板是否存在。正式商品看板已遷移到 V3 shell。
if not os.path.exists(os.path.join(TEMPLATE_DIR, 'dashboard_v2.html')):
sys_log.warning(f"[Web] [Template] ⚠️ 警告: 找不到 dashboard_v2.html | Path: {TEMPLATE_DIR}")
app = Flask(__name__,
template_folder=TEMPLATE_DIR,
static_folder=STATIC_DIR)
app.config['SEND_FILE_MAX_AGE_DEFAULT'] = timedelta(days=7)
@app.url_defaults
def add_static_asset_version(endpoint, values):
"""讓靜態資源 URL 跟著系統版本破快取,搭配長快取標頭使用。"""
if endpoint == 'static' and values.get('filename') and 'v' not in values:
values['v'] = SYSTEM_VERSION
# ==========================================
# 🔒 Flask 安全配置
@@ -217,12 +230,12 @@ csrf.exempt(ai_bp) # ICAIM API 使用內部呼叫,不需要 CSRF
sys_log.info("[Blueprint] ✅ AI 智慧文案系統 Blueprint 已註冊")
# ==========================================
# 🔧 Blueprint 註冊 - CI/CD Dashboard
# 🔧 Blueprint 註冊 - 部署監控
# ==========================================
from routes.cicd_routes import cicd_bp
app.register_blueprint(cicd_bp)
csrf.exempt(cicd_bp) # CI/CD API doesn't need CSRF
sys_log.info("[Blueprint] CI/CD Dashboard Blueprint registered")
csrf.exempt(cicd_bp) # 部署監控 API 使用內部呼叫,不需要 CSRF
sys_log.info("[Blueprint] ✅ 部署監控 Blueprint 已註冊")
# ==========================================
# 🔧 Blueprint 註冊 - Code Review 系統
@@ -301,6 +314,20 @@ csrf.exempt(bot_api_bp) # Bot API 使用 Token 認證,不需要 CSRF
sys_log.info("[Blueprint] ✅ Bot API Blueprint 已註冊")
# ==========================================
# Phase 27/28: Admin Observability Dashboard
# Operation Ollama-First v5.0 戰役觀測前端
# 路徑:/admin/ai_calls / promotion_review / quality_trend / host_health
# ==========================================
try:
from routes.admin_observability_routes import admin_observability_bp
app.register_blueprint(admin_observability_bp)
# Phase 33 Critic 修補:拿掉 csrf_exempt + 全路由加 @login_requiredauth bypass 修正)
sys_log.info("[Blueprint] ✅ Admin Observability Blueprint 已註冊Phase 27/28/33-secured")
except ImportError as _imp_err:
sys_log.warning("[Blueprint] ⚠️ Admin Observability 註冊失敗: %s", _imp_err)
# ==========================================
# Elephant Alpha AI Agent Super Orchestrator Blueprint
# ==========================================
@@ -364,6 +391,13 @@ from routes.pchome_routes import pchome_bp
app.register_blueprint(pchome_bp)
sys_log.info("[Blueprint] ✅ pchome_bp 已註冊")
from routes.market_intel_routes import market_intel_bp
app.register_blueprint(market_intel_bp)
sys_log.info("[Blueprint] ✅ market_intel_bp 已註冊")
from routes.market_intel_review_routes import market_intel_review_bp
app.register_blueprint(market_intel_review_bp)
sys_log.info("[Blueprint] ✅ market_intel_review_bp 已註冊")
# V-Fix: 註冊 slugify 函數供模板使用(實作搬至 utils/text_helpers.py
from utils.text_helpers import slugify # noqa: E402
@@ -384,6 +418,10 @@ EXPECTED_METADATA_TABLES = {
'import_jobs', 'import_config', 'notification_templates', 'ppt_reports',
'vendor_stockout', 'vendor_list', 'vendor_emails', 'email_send_log',
'realtime_sales_monthly',
'market_platforms', 'market_campaigns', 'market_campaign_snapshots',
'market_campaign_products', 'market_product_price_history',
'market_product_matches', 'market_crawler_runs',
'market_alert_review_queue',
}
@@ -398,18 +436,24 @@ verify_metadata_tables()
# ==========================================
# 🔧 全域模板變數注入 (Context Processor)
# ==========================================
from config import METABASE_URL, GRIST_URL
@app.context_processor
def inject_global_vars():
"""注入全域變數到所有模板"""
return {
'metabase_url': METABASE_URL,
'grist_url': GRIST_URL,
'metabase_url': '/metabase',
'grist_url': '/grist',
'datetime_now': datetime.now(TAIPEI_TZ).strftime('%Y-%m-%d %H:%M:%S'),
'webcrumbs_config': {
'enabled': WEBCRUMBS_ENABLED,
'base_url': WEBCRUMBS_BASE_URL,
'runtime_url': WEBCRUMBS_RUNTIME_URL,
'runtime_version': WEBCRUMBS_RUNTIME_VERSION,
'plugin_base_url': WEBCRUMBS_PLUGIN_BASE_URL,
'asset_upstream_url': WEBCRUMBS_ASSET_UPSTREAM_URL,
},
}
sys_log.info("[Template] ✅ 全域模板變數已注入 (metabase_url, grist_url)")
sys_log.info("[Template] ✅ 全域模板變數已注入 (metabase_url, grist_url, webcrumbs_config)")
# ================= 🛠️ V9.72: 分類設定管理核心 =================
CATEGORIES_JSON_PATH = os.path.join(BASE_DIR, 'data', 'categories.json')
@@ -599,6 +643,8 @@ def refresh_session():
在每次請求時自動刷新 Session避免長時間閒置後突然斷線
只要用戶有任何操作Session 就會自動延長
"""
if request.endpoint == 'static':
return
if session.get('logged_in'):
session.modified = True # 標記 Session 已修改,觸發 Cookie 更新

174
config.py
View File

@@ -1,6 +1,7 @@
import os
import json
import sys
from urllib.parse import urlparse
from dotenv import load_dotenv
# 載入 .env 環境變數
@@ -111,6 +112,64 @@ EMAIL_RECEIVER = os.getenv('EMAIL_RECEIVER', '')
# ==========================================
PUBLIC_URL = os.getenv('PUBLIC_URL', 'https://mo.wooo.work')
def _env_bool(name: str, default: str = 'false') -> bool:
return os.getenv(name, default).strip().lower() in {'1', 'true', 'yes', 'on'}
def _safe_public_http_url(value: str) -> str:
"""只接受 http(s) URL避免模板把 javascript/data URI 輸出成 script src。"""
candidate = (value or '').strip().rstrip('/')
if not candidate:
return ''
parsed = urlparse(candidate)
if parsed.scheme not in {'http', 'https'} or not parsed.netloc:
return ''
return candidate
def _safe_webcrumbs_reference(value: str) -> str:
"""允許 http(s) URL 或 momo-pro 同源絕對路徑,供 script/plugin URL 使用。"""
candidate = (value or '').strip().rstrip('/')
if not candidate:
return ''
if candidate.startswith('/') and not candidate.startswith('//') and '\\' not in candidate:
return candidate
return _safe_public_http_url(candidate)
# Webcrumbs 共用 microfrontend runtime。
# 預設透過 momo-pro 同源 proxy 讀 188 Shared UI Hub避免正式頁面被跨域 TLS 狀態卡住。
WEBCRUMBS_ENABLED = _env_bool('WEBCRUMBS_ENABLED', 'true')
WEBCRUMBS_BASE_URL = _safe_public_http_url(
os.getenv('WEBCRUMBS_BASE_URL', 'https://webcrumbs.wooo.work')
)
WEBCRUMBS_RUNTIME_VERSION = os.getenv('WEBCRUMBS_RUNTIME_VERSION', 'shared-ui-poc-0.1.0').strip().strip('/')
WEBCRUMBS_RUNTIME_PATH = os.getenv(
'WEBCRUMBS_RUNTIME_PATH',
'/webcrumbs-assets/loader/webcrumbs-compatible-loader.js',
).strip()
_webcrumbs_runtime_url = os.getenv('WEBCRUMBS_RUNTIME_URL', '').strip()
WEBCRUMBS_RUNTIME_URL = _safe_webcrumbs_reference(_webcrumbs_runtime_url)
if not WEBCRUMBS_RUNTIME_URL:
WEBCRUMBS_RUNTIME_URL = _safe_webcrumbs_reference(WEBCRUMBS_RUNTIME_PATH)
WEBCRUMBS_PLUGIN_BASE_URL = _safe_webcrumbs_reference(
os.getenv(
'WEBCRUMBS_PLUGIN_BASE_URL',
'/webcrumbs-assets/plugins',
)
)
WEBCRUMBS_ASSET_UPSTREAM_URL = _safe_public_http_url(
os.getenv('WEBCRUMBS_ASSET_UPSTREAM_URL', 'http://192.168.0.188:18088')
)
# ==========================================
# 市場情報模組設定(預設全部關閉)
# ==========================================
MARKET_INTEL_ENABLED = os.getenv('MARKET_INTEL_ENABLED', 'false').lower() == 'true'
MARKET_INTEL_CRAWLER_ENABLED = os.getenv('MARKET_INTEL_CRAWLER_ENABLED', 'false').lower() == 'true'
MARKET_INTEL_WRITE_ENABLED = os.getenv('MARKET_INTEL_WRITE_ENABLED', 'false').lower() == 'true'
# 補上 EXCEL_EXPORT_DIR 定義
EXCEL_EXPORT_DIR = os.path.join(DATA_DIR, 'excel_exports')
@@ -222,28 +281,117 @@ GRIST_URL = os.getenv('GRIST_URL', '') # Grist 資料協作連結
# ==========================================
# AI 服務設定
# ==========================================
_APPROVED_OLLAMA_HOST_SUBSTRINGS = (
'34.87.90.216:11434',
'34.21.145.224:11434',
'192.168.0.111:11434',
'192.168.0.110:11435',
'192.168.0.110:11436',
)
def _static_approved_ollama_env(name: str, default: str = '') -> str:
"""Import-time safe Ollama host env reader; never probes network."""
value = os.getenv(name, '').strip()
if value and any(approved in value for approved in _APPROVED_OLLAMA_HOST_SUBSTRINGS):
return value
return default
_STATIC_OLLAMA_PRIMARY = _static_approved_ollama_env(
'OLLAMA_HOST_PRIMARY',
'http://34.87.90.216:11434',
)
# Hermes AI Service (競價情報分析)
HERMES_URL = os.getenv('HERMES_URL', 'http://192.168.0.111:11434')
# V-New (ADR-027 Phase 2):所有 host 解析必須 lazy禁止 import-time freeze。
# 理由import 時 GCP 還沒探測resolve_ollama_host 內部 cache 120s
# 若 freeze 到 module attr主機 GCP 後來掛掉、cache 失效仍取不到新值。
def get_hermes_url():
"""Lazy 取得 Hermes 主機(每次呼叫都嘗試 resolve內部有 120s cache
優先序:
1. env HERMES_URL僅接受 GCP-A/GCP-B/111
2. resolve_ollama_host()GCP 優先 / 111 備援)
3. 兜底 http://192.168.0.111:11434防 ImportError
"""
try:
from services.ollama_service import approved_ollama_env
env_val = approved_ollama_env('HERMES_URL')
except Exception:
env_val = os.getenv('HERMES_URL', '').strip()
if env_val:
return env_val
try:
from services.ollama_service import resolve_ollama_host
return resolve_ollama_host()
except Exception:
return 'http://192.168.0.111:11434'
def get_embedding_host():
"""Lazy 取得 Embedding 主機。
優先序env EMBEDDING_HOST僅接受 GCP-A/GCP-B/111> get_hermes_url()。
"""
try:
from services.ollama_service import approved_ollama_env
env_val = approved_ollama_env('EMBEDDING_HOST')
except Exception:
env_val = os.getenv('EMBEDDING_HOST', '').strip()
if env_val:
return env_val
return get_hermes_url()
def get_ollama_host():
"""Lazy 取得 Ollama 主機(一般 LLM 推理用)。
優先序env OLLAMA_HOST僅接受 GCP-A/GCP-B/111> resolve_ollama_host()。
與舊 module-level OLLAMA_HOST 不同:本函數不會 freeze 結果,每次呼叫都重新 resolve。
"""
try:
from services.ollama_service import approved_ollama_env
env_val = approved_ollama_env('OLLAMA_HOST')
except Exception:
env_val = os.getenv('OLLAMA_HOST', '').strip()
if env_val:
return env_val
try:
from services.ollama_service import resolve_ollama_host
return resolve_ollama_host()
except Exception:
return 'http://192.168.0.111:11434'
# 向下相容:舊 caller 仍可 `from config import HERMES_URL`,但此常數不得
# import-time probe也不得在 GCP 短暫不可用時 freeze 到 111新 caller 應
# 改用 `get_hermes_url()` 或 `OllamaService` 取得動態三主機級聯結果。
HERMES_URL = _static_approved_ollama_env('HERMES_URL', _STATIC_OLLAMA_PRIMARY)
HERMES_TIMEOUT = int(os.getenv('HERMES_TIMEOUT', '120')) # 秒;批量 300 筆預估 ~90s
# Embedding 服務ADR-003 對齊embedding 走 Hermes 主機,內網免認證)
# 預設 fallback 到 HERMES_URL若需獨立 embedding 主機可透過 env 覆寫
EMBEDDING_HOST = os.getenv('EMBEDDING_HOST', HERMES_URL)
# 向下相容;新 caller 應改用 `get_embedding_host()` 或
# `OllamaService.generate_embedding()`,不可依賴 import-time 探測結果。
EMBEDDING_HOST = _static_approved_ollama_env('EMBEDDING_HOST', HERMES_URL)
EMBEDDING_TIMEOUT = int(os.getenv('EMBEDDING_TIMEOUT', os.getenv('OLLAMA_EMBED_TIMEOUT', '45')))
# SSH Jump Configuration (AIOps AutoHeal)
SSH_JUMP_HOST = os.getenv('SSH_JUMP_HOST', '192.168.0.110')
SSH_JUMP_USER = os.getenv('SSH_JUMP_USER', 'wooo')
SSH_TARGET_HOST = os.getenv('SSH_TARGET_HOST', '192.168.0.188')
SSH_TARGET_USER = os.getenv('SSH_TARGET_USER', 'ollama')
# Ollama 本地 AI 服務
OLLAMA_HOST = os.getenv('OLLAMA_HOST', 'https://ollama.wooo.work/ollama')
# ADR-027 Phase 2OLLAMA_HOST 改為 lazy resolve禁止寫死 nginx URL 繞過 GCP 優先策略。
# 舊行為:寫死 'https://ollama.wooo.work/ollama' → 任何 import 都跳過 GCP 探測。
# 新行為env OLLAMA_HOST 優先;否則動態 caller 走 resolve_ollama_host()GCP 優先 / 111 備援)。
# 向下相容:保留 OLLAMA_HOST module attribute但不再於 import 時呼叫 get_ollama_host()。
# 新 caller 應改用 `from config import get_ollama_host` + `host = get_ollama_host()`。
OLLAMA_HOST = _static_approved_ollama_env('OLLAMA_HOST', _STATIC_OLLAMA_PRIMARY)
OLLAMA_MODEL = os.getenv('OLLAMA_MODEL', 'gemma3:4b')
# Google Gemini AI 雲端服務
GEMINI_API_KEY = os.getenv('GEMINI_API_KEY', '')
GEMINI_MODEL = os.getenv('GEMINI_MODEL', 'gemini-1.5-flash')
# Gemini is emergency fallback only. The hard kill switch defaults to true, so
# GEMINI_API_KEY/GEMINI_FALLBACK_ENABLED cannot create paid egress by accident.
GEMINI_API_HARD_DISABLED = os.getenv('GEMINI_API_HARD_DISABLED', 'true')
GEMINI_FALLBACK_ENABLED = os.getenv('GEMINI_FALLBACK_ENABLED', 'false')
GEMINI_ALLOWED_CONTEXTS = os.getenv('GEMINI_ALLOWED_CONTEXTS', '')
# 預設 AI 提供者: 'ollama' (本地免費) 或 'gemini' (雲端付費)
AI_PROVIDER = os.getenv('AI_PROVIDER', 'ollama')
@@ -254,7 +402,7 @@ YOUTUBE_API_KEY = os.getenv('YOUTUBE_API_KEY', '')
# ==========================================
# 系統版本與路徑
# ==========================================
SYSTEM_VERSION = "V10.76"
SYSTEM_VERSION = "V10.653"
LOG_FILE_PATH = os.path.join(BASE_DIR, 'logs/system.log')
public_url = PUBLIC_URL # 用於模板顯示
@@ -265,4 +413,8 @@ def validate_critical_config():
for var in optional_vars:
if not os.getenv(var):
warnings.append(f"[Config] 選用設定 {var} 未設,部分功能可能停用")
if WEBCRUMBS_ENABLED and not WEBCRUMBS_RUNTIME_URL:
warnings.append("[Config] WEBCRUMBS_ENABLED=true 但 WEBCRUMBS_RUNTIME_URL 無效Webcrumbs runtime 將不會載入")
if WEBCRUMBS_ENABLED and WEBCRUMBS_RUNTIME_URL.startswith('/webcrumbs-assets/') and not WEBCRUMBS_ASSET_UPSTREAM_URL:
warnings.append("[Config] Webcrumbs 使用同源 asset proxy但 WEBCRUMBS_ASSET_UPSTREAM_URL 無效")
return warnings

View File

@@ -1,8 +1,36 @@
# AI history and template models
from sqlalchemy import Column, Integer, String, DateTime, Text, Boolean, Float
from sqlalchemy import BigInteger, Column, DateTime, Integer, Numeric, String, Text, Boolean, Float
from sqlalchemy.dialects import postgresql
from sqlalchemy.ext.compiler import compiles
from sqlalchemy.types import JSON, UserDefinedType
from database.models import Base
from datetime import datetime
class Vector(UserDefinedType):
"""pgvector column with a SQLite-safe fallback for local metadata tests."""
cache_ok = True
def __init__(self, dimensions):
self.dimensions = dimensions
def get_col_spec(self, **kw):
return f"VECTOR({self.dimensions})"
@compiles(Vector, "sqlite")
def _compile_vector_sqlite(type_, compiler, **kw):
return "TEXT"
def _jsonb_type():
return JSON().with_variant(postgresql.JSONB, "postgresql")
def _bigint_array_type():
return Text().with_variant(postgresql.ARRAY(BigInteger), "postgresql")
class AIGenerationHistory(Base):
"""
AI generation history tracking
@@ -151,6 +179,150 @@ class AIInsight(Base):
}
class AICall(Base):
"""ai_calls unified LLM call telemetry table (migration 024)."""
__tablename__ = 'ai_calls'
__table_args__ = {'extend_existing': True}
id = Column(BigInteger, primary_key=True, autoincrement=True)
called_at = Column(DateTime(timezone=True), default=datetime.now, nullable=False)
caller = Column(String(64), nullable=False)
provider = Column(String(32), nullable=False)
model = Column(String(128), nullable=False)
input_tokens = Column(Integer, default=0, nullable=False)
output_tokens = Column(Integer, default=0, nullable=False)
duration_ms = Column(Integer)
status = Column(String(16), nullable=False)
fallback_to = Column(String(64))
cost_usd = Column(Numeric(10, 6), default=0, nullable=False)
cache_hit = Column(Boolean, default=False, nullable=False)
rag_hit = Column(Boolean, default=False, nullable=False)
request_id = Column(String(64))
error = Column(Text)
meta = Column(_jsonb_type())
class MCPCall(Base):
"""mcp_calls MCP server call telemetry table (migration 025)."""
__tablename__ = 'mcp_calls'
__table_args__ = {'extend_existing': True}
id = Column(BigInteger, primary_key=True, autoincrement=True)
called_at = Column(DateTime(timezone=True), default=datetime.now, nullable=False)
caller = Column(String(64), nullable=False)
server = Column(String(64), nullable=False)
tool = Column(String(128), nullable=False)
input_args = Column(_jsonb_type())
output_size = Column(Integer)
duration_ms = Column(Integer)
status = Column(String(16), nullable=False)
error = Column(Text)
cost_usd = Column(Numeric(10, 6), default=0, nullable=False)
cache_hit = Column(Boolean, default=False, nullable=False)
request_id = Column(String(64))
insight_id = Column(BigInteger)
class AICallBudget(Base):
"""ai_call_budgets budget guardrail table (migration 025)."""
__tablename__ = 'ai_call_budgets'
__table_args__ = {'extend_existing': True}
id = Column(Integer, primary_key=True, autoincrement=True)
period = Column(String(16), nullable=False)
provider = Column(String(32))
budget_usd = Column(Numeric(10, 2), nullable=False)
alert_pct = Column(Integer, default=80, nullable=False)
updated_at = Column(DateTime(timezone=True), default=datetime.now)
class RAGQueryLog(Base):
"""rag_query_log RAG recall telemetry table (migration 027)."""
__tablename__ = 'rag_query_log'
__table_args__ = {'extend_existing': True}
id = Column(BigInteger, primary_key=True, autoincrement=True)
queried_at = Column(DateTime(timezone=True), default=datetime.now, nullable=False)
caller = Column(String(64), nullable=False)
query_text = Column(Text, nullable=False)
query_embedding = Column(Vector(1024))
embedding_signature = Column(String(64))
top_k = Column(Integer, default=5, nullable=False)
threshold = Column(Numeric(4, 3), default=0.85, nullable=False)
hit_count = Column(Integer, default=0, nullable=False)
used_results = Column(_bigint_array_type())
saved_call = Column(Boolean, default=False, nullable=False)
feedback_score = Column(Integer)
request_id = Column(String(64))
class LearningEpisode(Base):
"""learning_episodes PromotionGate staging table (migration 028)."""
__tablename__ = 'learning_episodes'
__table_args__ = {'extend_existing': True}
id = Column(BigInteger, primary_key=True, autoincrement=True)
created_at = Column(DateTime(timezone=True), default=datetime.now, nullable=False)
episode_type = Column(String(32), nullable=False)
source_table = Column(String(32))
source_id = Column(BigInteger)
distilled_text = Column(Text, nullable=False)
embedding = Column(Vector(1024))
embedding_signature = Column(String(64))
quality_score = Column(Numeric(4, 3), default=0.0, nullable=False)
weight = Column(Numeric(4, 3), default=0.5, nullable=False)
promotion_status = Column(String(32), default='pending', nullable=False)
insight_id = Column(BigInteger)
rejected_reason = Column(Text)
human_approver = Column(String(64))
reviewed_at = Column(DateTime(timezone=True))
class HostHealthProbe(Base):
"""host_health_probes Ollama failover health history table (migration 029)."""
__tablename__ = 'host_health_probes'
__table_args__ = {'extend_existing': True}
id = Column(BigInteger, primary_key=True, autoincrement=True)
probed_at = Column(DateTime(timezone=True), default=datetime.now, nullable=False)
host_label = Column(String(64), nullable=False)
host_url = Column(String(256), nullable=False)
healthy = Column(Boolean, nullable=False)
unhealthy_mark = Column(Boolean, default=False, nullable=False)
models_count = Column(Integer, default=0)
response_ms = Column(Integer)
error_msg = Column(Text)
class PPTAuditResult(Base):
"""ppt_audit_results PPT vision audit history table (migration 030)."""
__tablename__ = 'ppt_audit_results'
__table_args__ = {'extend_existing': True}
id = Column(BigInteger, primary_key=True, autoincrement=True)
audited_at = Column(DateTime(timezone=True), default=datetime.now, nullable=False)
pptx_filename = Column(String(256), nullable=False)
pptx_size_kb = Column(Integer)
pptx_mtime = Column(DateTime(timezone=True))
vision_enabled = Column(Boolean, nullable=False)
audit_status = Column(String(32), nullable=False)
issues_count = Column(Integer, default=0)
issues_found = Column(_jsonb_type())
confidence = Column(Numeric(4, 3))
duration_ms = Column(Integer)
error_msg = Column(Text)
reviewer_notes = Column(Text)
__all__ = [
"AIGenerationHistory", "AIPromptTemplate", "AIUsageTracking", "AIInsight",
"AICall", "MCPCall", "AICallBudget", "RAGQueryLog", "LearningEpisode",
"HostHealthProbe", "PPTAuditResult",
]

View File

@@ -1,4 +1,4 @@
from sqlalchemy import Column, Integer, String, DateTime, Text, Boolean, ForeignKey, Index, Float
from sqlalchemy import CheckConstraint, Column, Integer, String, DateTime, Text, Boolean, ForeignKey, Index, Float
from sqlalchemy.orm import relationship
from database.models import Base
from datetime import datetime
@@ -55,6 +55,29 @@ class ActionPlan(Base):
executed_at = Column(DateTime, nullable=True)
__table_args__ = (
CheckConstraint(
"action_type IS NOT NULL OR created_by IS NOT NULL",
name="chk_action_plans_source_marker",
),
CheckConstraint(
"action_type IS NULL OR action_type IN ('auto', 'code_review_fix', 'openclaw_recommendation')",
name="chk_action_plans_action_type",
),
CheckConstraint(
"created_by IS NULL OR created_by IN ("
"'nemotron', 'openclaw', 'code_review_pipeline', "
"'ai_orchestrator', 'watcher_agent', 'agent_actions', "
"'elephant_alpha', 'manual', 'system'"
")",
name="chk_action_plans_created_by",
),
CheckConstraint(
"status IS NULL OR status IN ("
"'pending', 'approved', 'rejected', 'executed', "
"'auto_pending', 'auto_disabled', 'pending_review'"
")",
name="chk_action_plans_status",
),
Index('idx_action_plans_type', 'action_type'),
Index('idx_action_plan_sku_status', 'sku', 'status'),
Index('idx_action_plan_created', 'created_at'),
@@ -111,16 +134,19 @@ class Incident(Base):
task_name = Column(String(100), nullable=False)
error_type = Column(String(50), nullable=False)
error_message = Column(Text, nullable=False)
error_traceback = Column(Text)
traceback_str = Column(Text)
severity = Column(String(20), default='medium')
status = Column(String(20), default='open') # open/healing/closed/escalated
retry_count = Column(Integer, default=0)
playbook_id = Column(Integer, ForeignKey('playbooks.id'), nullable=True)
matched_playbook_id = Column(Integer, ForeignKey('playbooks.id'), nullable=True)
resolved_at = Column(DateTime, nullable=True)
created_at = Column(DateTime, default=datetime.now)
updated_at = Column(DateTime, default=datetime.now)
# Relationship
playbook = relationship("Playbook", backref="incidents")
playbook = relationship("Playbook", foreign_keys=[matched_playbook_id], backref="incidents")
class Playbook(Base):

View File

@@ -0,0 +1,107 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""外部市場來源與報價的正規化 ORM models。"""
from datetime import datetime, timedelta, timezone
from sqlalchemy import (
Boolean,
Column,
DateTime,
Float,
ForeignKey,
Index,
Integer,
String,
Text,
UniqueConstraint,
)
from sqlalchemy.orm import relationship
from database.models import Base
TAIPEI_TZ = timezone(timedelta(hours=8))
def taipei_now():
return datetime.now(TAIPEI_TZ).replace(tzinfo=None)
class ExternalMarketSource(Base):
"""外部市場資料來源,例如 MOMO 參考價、蝦皮 API、酷澎 CSV。"""
__tablename__ = "external_market_sources"
id = Column(Integer, primary_key=True, autoincrement=True)
code = Column(String(80), unique=True, nullable=False, index=True)
display_name = Column(String(160), nullable=False)
platform_code = Column(String(80), nullable=False, index=True)
source_kind = Column(String(60), nullable=False, index=True)
status = Column(String(40), default="paused", nullable=False, index=True)
enabled = Column(Boolean, default=False, nullable=False)
write_enabled = Column(Boolean, default=False, nullable=False)
allowed_input_methods_json = Column(Text)
quality_policy_json = Column(Text)
plain_note = Column(Text)
created_at = Column(DateTime, default=taipei_now, nullable=False)
updated_at = Column(DateTime, default=taipei_now, onupdate=taipei_now, nullable=False)
offers = relationship("ExternalOffer", back_populates="source")
__table_args__ = (
Index("idx_external_market_sources_status", "status", "enabled"),
)
class ExternalOffer(Base):
"""正規化後的外部商品報價。"""
__tablename__ = "external_offers"
id = Column(Integer, primary_key=True, autoincrement=True)
source_code = Column(String(80), ForeignKey("external_market_sources.code"), nullable=False, index=True)
platform_code = Column(String(80), nullable=False, index=True)
source_product_id = Column(String(220), nullable=False, index=True)
source_offer_key = Column(String(260), nullable=False)
title = Column(Text, nullable=False)
brand = Column(String(180), index=True)
category_text = Column(String(320), index=True)
product_url = Column(Text)
image_url = Column(Text)
price = Column(Float)
original_price = Column(Float)
currency = Column(String(12), default="TWD", nullable=False)
stock_status = Column(String(80), index=True)
sold_count = Column(Integer)
rating = Column(Float)
review_count = Column(Integer)
observed_at = Column(DateTime, default=taipei_now, nullable=False, index=True)
expires_at = Column(DateTime, index=True)
ingestion_method = Column(String(60), nullable=False, index=True)
connector_key = Column(String(120), index=True)
pchome_product_id = Column(String(120), index=True)
momo_sku = Column(String(80), index=True)
match_status = Column(String(40), default="unmatched", nullable=False, index=True)
quality_score = Column(Float, default=0.0, nullable=False)
data_quality_status = Column(String(40), default="needs_review", nullable=False, index=True)
quality_notes_json = Column(Text)
raw_payload_json = Column(Text)
created_at = Column(DateTime, default=taipei_now, nullable=False)
updated_at = Column(DateTime, default=taipei_now, onupdate=taipei_now, nullable=False)
source = relationship("ExternalMarketSource", back_populates="offers")
__table_args__ = (
UniqueConstraint(
"source_code",
"source_product_id",
"observed_at",
"ingestion_method",
name="uq_external_offer_source_product_observed",
),
Index("idx_external_offers_source_seen", "source_code", "observed_at"),
Index("idx_external_offers_platform_product", "platform_code", "source_product_id"),
Index("idx_external_offers_pchome_product", "pchome_product_id", "source_code"),
Index("idx_external_offers_match_quality", "match_status", "data_quality_status", "quality_score"),
)

View File

@@ -10,7 +10,19 @@ from .user_models import User, LoginHistory # noqa: F401 - 必須在 trend_mode
from .edm_models import PromoProduct # V-Fix: 確保 EDM 模型被註冊,以便自動建表
from .trend_models import TrendRecord, TrendKeyword, TrendAnalysis, WebSearchCache, TelegramUser # noqa: F401 - 趨勢資料表
from .permission_models import Permission, UserPermission # noqa: F401 - 確保權限表被 Base.metadata 管理
from .ai_models import AIGenerationHistory, AIPromptTemplate, AIUsageTracking, AIInsight # noqa: F401 - AI history/template 表
from .ai_models import ( # noqa: F401 - AI history/template + v5 telemetry
AIGenerationHistory,
AIPromptTemplate,
AIUsageTracking,
AIInsight,
AICall,
MCPCall,
AICallBudget,
RAGQueryLog,
LearningEpisode,
HostHealthProbe,
PPTAuditResult,
)
from .autoheal_models import ( # noqa: F401 - ADR-013 AIOps 自動修復表
AgentContext,
ActionPlan,
@@ -23,8 +35,20 @@ from .autoheal_models import ( # noqa: F401 - ADR-013 AIOps 自動修復表
from .import_models import ImportJob, ImportConfig # noqa: F401 - 確保 import_jobs/import_config 被 Base.metadata 管理
from .notification_models import NotificationTemplate # noqa: F401 - 確保 notification_templates 表被 Base.metadata 管理
from .ppt_reports import PPTReport # noqa: F401 - 確保 ppt_reports 表被 Base.metadata 管理
from .ppt_generation_runs import PPTGenerationRun # noqa: F401 - 確保 ppt_generation_runs 表被 Base.metadata 管理
from .vendor_models import VendorStockout, VendorList, VendorEmail, EmailSendLog # noqa: F401 - 確保 vendor 表被 Base.metadata 管理
from .realtime_sales_models import RealtimeSalesMonthly # noqa: F401 - 確保 realtime_sales_monthly 被 Base.metadata 管理
from .market_intel_models import ( # noqa: F401 - ADR-035 market_* 表
MarketPlatform,
MarketCampaign,
MarketCampaignSnapshot,
MarketCampaignProduct,
MarketProductPriceHistory,
MarketProductMatch,
MarketCrawlerRun,
MarketAlertReviewQueue,
)
from .external_market_models import ExternalMarketSource, ExternalOffer # noqa: F401 - 外部市場正規化表
# 🚩 導入優化後的日誌管理模組
from utils.logger_manager import SystemLogger

View File

@@ -0,0 +1,267 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""跨平台市場活動情報 ORM models。"""
from datetime import datetime, timedelta, timezone
from sqlalchemy import (
Boolean,
Column,
DateTime,
Float,
ForeignKey,
Index,
Integer,
String,
Text,
UniqueConstraint,
)
from sqlalchemy.orm import relationship
from database.models import Base
TAIPEI_TZ = timezone(timedelta(hours=8))
def taipei_now():
"""取得台北時間 naive datetime符合專案 DB 時間規範。"""
return datetime.now(TAIPEI_TZ).replace(tzinfo=None)
class MarketPlatform(Base):
"""市場平台設定,例如 MOMO / PChome / Coupang / Shopee。"""
__tablename__ = "market_platforms"
id = Column(Integer, primary_key=True, autoincrement=True)
code = Column(String(50), unique=True, nullable=False, index=True)
name = Column(String(120), nullable=False)
base_url = Column(String(500))
enabled = Column(Boolean, default=False, nullable=False)
crawl_policy_json = Column(Text)
created_at = Column(DateTime, default=taipei_now, nullable=False)
updated_at = Column(DateTime, default=taipei_now, onupdate=taipei_now, nullable=False)
campaigns = relationship("MarketCampaign", back_populates="platform")
class MarketCampaign(Base):
"""跨平台活動檔期。"""
__tablename__ = "market_campaigns"
id = Column(Integer, primary_key=True, autoincrement=True)
platform_code = Column(String(50), ForeignKey("market_platforms.code"), nullable=False, index=True)
campaign_key = Column(String(200), nullable=False)
campaign_name = Column(String(500), nullable=False)
campaign_type = Column(String(80), index=True)
campaign_url = Column(Text)
start_at = Column(DateTime)
end_at = Column(DateTime)
status = Column(String(30), default="unknown", nullable=False, index=True)
discovered_at = Column(DateTime, default=taipei_now, nullable=False)
last_seen_at = Column(DateTime, default=taipei_now, nullable=False)
metadata_json = Column(Text)
platform = relationship("MarketPlatform", back_populates="campaigns")
snapshots = relationship("MarketCampaignSnapshot", back_populates="campaign")
products = relationship("MarketCampaignProduct", back_populates="campaign")
__table_args__ = (
UniqueConstraint("platform_code", "campaign_key", name="uq_market_campaign_platform_key"),
Index("idx_market_campaign_status_time", "status", "start_at", "end_at"),
)
class MarketCampaignSnapshot(Base):
"""活動頁每次爬取快照。"""
__tablename__ = "market_campaign_snapshots"
id = Column(Integer, primary_key=True, autoincrement=True)
campaign_id = Column(Integer, ForeignKey("market_campaigns.id"), nullable=False, index=True)
batch_id = Column(String(80), nullable=False, index=True)
crawled_at = Column(DateTime, default=taipei_now, nullable=False, index=True)
title = Column(String(500))
hero_text = Column(Text)
coupon_text = Column(Text)
raw_discount_text = Column(Text)
page_hash = Column(String(128), index=True)
raw_snapshot_path = Column(Text)
status = Column(String(30), default="success", nullable=False, index=True)
error_message = Column(Text)
metadata_json = Column(Text)
campaign = relationship("MarketCampaign", back_populates="snapshots")
__table_args__ = (
Index("idx_market_campaign_snapshot_campaign_time", "campaign_id", "crawled_at"),
)
class MarketCampaignProduct(Base):
"""活動頁中的平台商品快照主檔。"""
__tablename__ = "market_campaign_products"
id = Column(Integer, primary_key=True, autoincrement=True)
campaign_id = Column(Integer, ForeignKey("market_campaigns.id"), nullable=False, index=True)
platform_code = Column(String(50), nullable=False, index=True)
platform_product_id = Column(String(200), nullable=False, index=True)
product_url = Column(Text)
name = Column(String(500), nullable=False)
brand = Column(String(200), index=True)
image_url = Column(Text)
category_text = Column(String(300), index=True)
price = Column(Float)
original_price = Column(Float)
discount_text = Column(String(200))
discount_rate = Column(Float)
coupon_text = Column(Text)
stock_text = Column(String(200))
sold_count = Column(Integer)
rating = Column(Float)
review_count = Column(Integer)
rank_position = Column(Integer)
is_active = Column(Boolean, default=True, nullable=False, index=True)
first_seen_at = Column(DateTime, default=taipei_now, nullable=False)
last_seen_at = Column(DateTime, default=taipei_now, nullable=False, index=True)
metadata_json = Column(Text)
campaign = relationship("MarketCampaign", back_populates="products")
price_history = relationship("MarketProductPriceHistory", back_populates="market_product")
matches = relationship("MarketProductMatch", back_populates="market_product")
__table_args__ = (
UniqueConstraint(
"campaign_id",
"platform_code",
"platform_product_id",
name="uq_market_campaign_product",
),
Index("idx_market_product_platform_seen", "platform_code", "last_seen_at"),
Index("idx_market_product_discount", "discount_rate", "price"),
)
class MarketProductPriceHistory(Base):
"""市場商品價格歷史快照。"""
__tablename__ = "market_product_price_history"
id = Column(Integer, primary_key=True, autoincrement=True)
market_product_id = Column(Integer, ForeignKey("market_campaign_products.id"), nullable=False, index=True)
campaign_id = Column(Integer, ForeignKey("market_campaigns.id"), nullable=False, index=True)
platform_code = Column(String(50), nullable=False, index=True)
platform_product_id = Column(String(200), nullable=False, index=True)
price = Column(Float)
original_price = Column(Float)
discount_rate = Column(Float)
stock_text = Column(String(200))
sold_count = Column(Integer)
rank_position = Column(Integer)
crawled_at = Column(DateTime, default=taipei_now, nullable=False, index=True)
batch_id = Column(String(80), nullable=False, index=True)
metadata_json = Column(Text)
market_product = relationship("MarketCampaignProduct", back_populates="price_history")
__table_args__ = (
Index("idx_market_price_platform_time", "platform_code", "platform_product_id", "crawled_at"),
Index("idx_market_price_campaign_time", "campaign_id", "crawled_at"),
)
class MarketProductMatch(Base):
"""市場商品與我方 MOMO 商品的比對審核結果。"""
__tablename__ = "market_product_matches"
id = Column(Integer, primary_key=True, autoincrement=True)
market_product_id = Column(Integer, ForeignKey("market_campaign_products.id"), nullable=False, index=True)
momo_product_id = Column(Integer, ForeignKey("products.id"), index=True)
momo_i_code = Column(String(50), index=True)
match_score = Column(Float, default=0.0, nullable=False)
match_status = Column(String(30), default="needs_review", nullable=False, index=True)
match_reason_json = Column(Text)
created_at = Column(DateTime, default=taipei_now, nullable=False)
reviewed_at = Column(DateTime)
reviewed_by = Column(String(120))
market_product = relationship("MarketCampaignProduct", back_populates="matches")
__table_args__ = (
UniqueConstraint("market_product_id", "momo_i_code", name="uq_market_product_momo_match"),
Index("idx_market_match_status_score", "match_status", "match_score"),
)
class MarketCrawlerRun(Base):
"""市場情報爬蟲執行紀錄。"""
__tablename__ = "market_crawler_runs"
id = Column(Integer, primary_key=True, autoincrement=True)
platform_code = Column(String(50), index=True)
crawler_name = Column(String(120), nullable=False, index=True)
campaign_id = Column(Integer, ForeignKey("market_campaigns.id"), index=True)
batch_id = Column(String(80), nullable=False, index=True)
started_at = Column(DateTime, default=taipei_now, nullable=False, index=True)
finished_at = Column(DateTime)
status = Column(String(30), default="started", nullable=False, index=True)
dry_run = Column(Boolean, default=True, nullable=False)
pages_found = Column(Integer, default=0, nullable=False)
products_found = Column(Integer, default=0, nullable=False)
products_changed = Column(Integer, default=0, nullable=False)
error_count = Column(Integer, default=0, nullable=False)
error_message = Column(Text)
metadata_json = Column(Text)
__table_args__ = (
Index("idx_market_crawler_run_platform_time", "platform_code", "started_at"),
Index("idx_market_crawler_run_status_time", "status", "started_at"),
)
class MarketAlertReviewQueue(Base):
"""市場機會與威脅告警的人工審核佇列。"""
__tablename__ = "market_alert_review_queue"
id = Column(Integer, primary_key=True, autoincrement=True)
alert_candidate_id = Column(String(120), nullable=False, unique=True, index=True)
review_state = Column(String(40), default="draft", nullable=False, index=True)
priority_lane = Column(String(40), default="watch", nullable=False, index=True)
threshold_level = Column(String(40), nullable=False, index=True)
total_score = Column(Float, default=0.0, nullable=False)
evidence_bundle_id = Column(String(120), nullable=False, index=True)
dedupe_key = Column(String(240), nullable=False)
source_batch_id = Column(String(80), nullable=False, index=True)
campaign_id = Column(Integer, ForeignKey("market_campaigns.id"), index=True)
market_product_id = Column(Integer, ForeignKey("market_campaign_products.id"), index=True)
momo_i_code = Column(String(50), index=True)
reviewer_identity = Column(String(120))
review_action = Column(String(60))
review_reason = Column(Text)
reviewed_at = Column(DateTime)
previous_state = Column(String(40))
next_state = Column(String(40))
created_at = Column(DateTime, default=taipei_now, nullable=False)
updated_at = Column(DateTime, default=taipei_now, onupdate=taipei_now, nullable=False)
metadata_json = Column(Text)
__table_args__ = (
Index(
"idx_market_alert_review_queue_state_priority",
"review_state",
"priority_lane",
"created_at",
),
Index("ux_market_alert_review_queue_dedupe", "dedupe_key", unique=True),
Index(
"idx_market_alert_review_queue_bundle",
"evidence_bundle_id",
"source_batch_id",
),
)

View File

@@ -0,0 +1,32 @@
"""PPT 定期產出執行紀錄模型。"""
from datetime import datetime
from sqlalchemy import Column, DateTime, Integer, String, Text
from database.models import Base
class PPTGenerationRun(Base):
"""每次日/週/月/季/半年/年度 PPT 產出嘗試。"""
__tablename__ = "ppt_generation_runs"
id = Column(Integer, primary_key=True)
schedule_kind = Column(String(40), nullable=False, index=True)
report_type = Column(String(50), nullable=False, index=True)
target_label = Column(String(160))
status = Column(String(30), nullable=False)
parameters_json = Column(Text)
file_path = Column(String(500))
file_size = Column(Integer)
error_msg = Column(Text)
result_payload = Column(Text)
started_at = Column(DateTime, default=datetime.now, index=True)
finished_at = Column(DateTime)
def __repr__(self):
return (
f"<PPTGenerationRun(kind={self.schedule_kind}, "
f"type={self.report_type}, status={self.status})>"
)

View File

@@ -71,5 +71,40 @@ def repair_database_schema():
for col_name, ddl in promo_columns:
_ensure_column(engine, text, 'promo_products', col_name, ddl)
# V10.328: PChome/MOMO 比價診斷欄位。正式價差與待審嘗試都需可回溯
# URL、圖片、庫存與 matcher 結構化原因,避免「待比對」無法被人工處理。
json_type = 'JSONB' if DATABASE_TYPE == 'postgresql' else 'TEXT'
competitor_price_columns = [
('competitor_product_url', "ALTER TABLE competitor_prices ADD COLUMN competitor_product_url TEXT"),
('competitor_image_url', "ALTER TABLE competitor_prices ADD COLUMN competitor_image_url TEXT"),
('competitor_stock', "ALTER TABLE competitor_prices ADD COLUMN competitor_stock INTEGER"),
('match_diagnostic_json', f"ALTER TABLE competitor_prices ADD COLUMN match_diagnostic_json {json_type}"),
('comparison_mode', "ALTER TABLE competitor_prices ADD COLUMN comparison_mode VARCHAR(40)"),
('hard_veto', "ALTER TABLE competitor_prices ADD COLUMN hard_veto BOOLEAN"),
('diagnostic_codes', f"ALTER TABLE competitor_prices ADD COLUMN diagnostic_codes {json_type}"),
]
competitor_history_columns = [
('competitor_product_url', "ALTER TABLE competitor_price_history ADD COLUMN competitor_product_url TEXT"),
('competitor_image_url', "ALTER TABLE competitor_price_history ADD COLUMN competitor_image_url TEXT"),
('competitor_stock', "ALTER TABLE competitor_price_history ADD COLUMN competitor_stock INTEGER"),
('match_diagnostic_json', f"ALTER TABLE competitor_price_history ADD COLUMN match_diagnostic_json {json_type}"),
('comparison_mode', "ALTER TABLE competitor_price_history ADD COLUMN comparison_mode VARCHAR(40)"),
('hard_veto', "ALTER TABLE competitor_price_history ADD COLUMN hard_veto BOOLEAN"),
('diagnostic_codes', f"ALTER TABLE competitor_price_history ADD COLUMN diagnostic_codes {json_type}"),
]
competitor_attempt_columns = [
('competitor_product_url', "ALTER TABLE competitor_match_attempts ADD COLUMN competitor_product_url TEXT"),
('competitor_image_url', "ALTER TABLE competitor_match_attempts ADD COLUMN competitor_image_url TEXT"),
('competitor_stock', "ALTER TABLE competitor_match_attempts ADD COLUMN competitor_stock INTEGER"),
('match_diagnostic_json', f"ALTER TABLE competitor_match_attempts ADD COLUMN match_diagnostic_json {json_type}"),
('comparison_mode', "ALTER TABLE competitor_match_attempts ADD COLUMN comparison_mode VARCHAR(40)"),
('hard_veto', "ALTER TABLE competitor_match_attempts ADD COLUMN hard_veto BOOLEAN"),
('diagnostic_codes', f"ALTER TABLE competitor_match_attempts ADD COLUMN diagnostic_codes {json_type}"),
]
for table_columns in (competitor_price_columns, competitor_history_columns, competitor_attempt_columns):
for col_name, ddl in table_columns:
table_name = ddl.split()[2]
_ensure_column(engine, text, table_name, col_name, ddl)
except Exception as e:
_log.error(f"[Database] [Schema] ❌ 資料庫修復失敗 | Error: {e}")

View File

@@ -53,7 +53,7 @@ HARBOR_PASSWORD="${HARBOR_PASSWORD:-Wooo_Harbor_2026}"
HARBOR_PROJECT="${HARBOR_PROJECT:-wooo}"
# Telegram 設定
TELEGRAM_BOT_TOKEN="${TELEGRAM_BOT_TOKEN:-8075645931:AAH-EGKMo8ZC4QJs-Nc1_0s92xHrGdQvdpg}"
TELEGRAM_BOT_TOKEN="${TELEGRAM_BOT_TOKEN:-<TELEGRAM_BOT_TOKEN>}"
TELEGRAM_CHAT_ID="${TELEGRAM_CHAT_ID:-5619078117}"
# =============================================================================

182
docker-compose.mcp.yml Normal file
View File

@@ -0,0 +1,182 @@
# =============================================================================
# Operation Ollama-First v5.0 / Phase 10 — MCP 自建 Stack
# =============================================================================
# 部署位置188 主機,與既有 momo-pro 容器共存
# 啟動方式docker compose -f docker-compose.mcp.yml up -d
# 啟用前置:
# 1. .env 加 TAVILY_API_KEYTavily 1000 free credits/月)
# 2. .env 加 EXA_API_KEYExa 備援)
# 3. 確認 188 防火牆 allow 172.x docker bridge 對外firecrawl 抓網頁)
#
# 4 個 MCP server 對應 ADR-031 (Phase 10) 規格:
# - postgres-mcp: Claude 直連 momo_pro DBread-only RBAC
# - mcp-omnisearch: 取代 Gemini GroundingTavily 主 + Exa 備
# - firecrawl-self: 自建爬蟲(含 Owen v5.0 護欄 #2 mem_limit:2g + chrome-reaper
# - filesystem-mcp: 跨主機檔案操作
#
# 護欄一覽ADR-033
# #2 Firecrawl mem_limit:2g + chrome-reaper sidecar + 1.8GB 告警
#
# 部署後驗收(給統帥):
# curl http://localhost:3001/health # postgres-mcp
# curl http://localhost:3002/health # firecrawl
# curl http://localhost:3003/health # omnisearch
# curl http://localhost:3004/health # filesystem
# =============================================================================
services:
# ─────────────────────────────────────────────────────────────────────────
# postgres-mcp: Claude 直連 momo_pro DBread-only
# ─────────────────────────────────────────────────────────────────────────
postgres-mcp:
image: mcp/postgres:latest
container_name: momo-mcp-postgres
restart: unless-stopped
init: true
ports:
- "127.0.0.1:3001:3000" # 僅 localhost 暴露(避免外網直連 DB
environment:
- POSTGRES_HOST=momo-db
- POSTGRES_PORT=5432
- POSTGRES_USER=mcp_readonly # 須在 momo-db 預先建 read-only role
- POSTGRES_PASSWORD=${MCP_POSTGRES_PASSWORD}
- POSTGRES_DB=momo_pro
# RBAC限制 SELECT 到熱表
- ALLOWED_TABLES=ai_insights,ai_calls,mcp_calls,daily_sales_snapshot,competitor_prices,products
networks:
- momo-shared
deploy:
resources:
limits:
memory: 256m
healthcheck:
test: ["CMD", "wget", "-qO-", "http://localhost:3000/health"]
interval: 30s
timeout: 5s
retries: 3
# ─────────────────────────────────────────────────────────────────────────
# mcp-omnisearch: 統一搜尋Tavily 主 + Exa 備)
# ─────────────────────────────────────────────────────────────────────────
mcp-omnisearch:
image: ghcr.io/spences10/mcp-omnisearch:latest
container_name: momo-mcp-omnisearch
restart: unless-stopped
init: true
ports:
- "127.0.0.1:3003:3000"
environment:
# 排除 Brave2026-02 已取消免費 tier
- TAVILY_API_KEY=${TAVILY_API_KEY} # 1000 free credits/月(主)
- EXA_API_KEY=${EXA_API_KEY} # 1000 free credits/月(備援)
- SEARCH_PROVIDER_ORDER=tavily,exa # fallback 順序
deploy:
resources:
limits:
memory: 512m
healthcheck:
test: ["CMD", "wget", "-qO-", "http://localhost:3000/health"]
interval: 30s
timeout: 5s
retries: 3
# ─────────────────────────────────────────────────────────────────────────
# firecrawl-self: 自建爬蟲(含 Owen v5.0 護欄 #2
# ─────────────────────────────────────────────────────────────────────────
firecrawl-self:
image: firecrawl/firecrawl:latest
container_name: momo-mcp-firecrawl
restart: unless-stopped
init: true
ports:
- "127.0.0.1:3002:3002"
environment:
- REDIS_URL=redis://firecrawl-redis:6379
- PLAYWRIGHT_MICROSERVICE_URL=http://firecrawl-playwright:3000
- PLAYWRIGHT_BROWSER_POOL_MAX=3 # ⭐ 護欄 #2瀏覽器池上限
- SCRAPE_TIMEOUT_MS=30000
- BULL_AUTH_KEY=${FIRECRAWL_AUTH_KEY:-momo-internal-only}
depends_on:
- firecrawl-redis
- firecrawl-playwright
deploy:
resources:
limits:
memory: 2g # ⭐ Owen v5.0 護欄 #2 硬上限
cpus: '1.5'
healthcheck:
test: ["CMD", "wget", "-qO-", "http://localhost:3002/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 60s
firecrawl-redis:
image: redis:7-alpine
container_name: momo-mcp-firecrawl-redis
restart: unless-stopped
deploy:
resources:
limits:
memory: 128m
firecrawl-playwright:
image: firecrawl/playwright:latest
container_name: momo-mcp-firecrawl-playwright
restart: unless-stopped
deploy:
resources:
limits:
memory: 1.5g
cpus: '1.0'
# ─────────────────────────────────────────────────────────────────────────
# chrome-reaper: 護欄 #2 — 每小時清 Chrome 殘留
# ─────────────────────────────────────────────────────────────────────────
chrome-reaper:
image: alpine:3
container_name: momo-mcp-chrome-reaper
restart: unless-stopped
command: |
sh -c '
apk add --no-cache docker-cli;
while true; do
echo "[reaper] $(date) cleaning Chrome zombies...";
docker exec momo-mcp-firecrawl-playwright \
sh -c "pkill -f \"chrome.*--type=zygote\" 2>/dev/null || true;
pkill -f \"chrome.*--type=renderer\" 2>/dev/null || true" \
2>/dev/null || true;
sleep 3600;
done
'
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
# ─────────────────────────────────────────────────────────────────────────
# filesystem-mcp: 跨主機檔案操作(限本地)
# ─────────────────────────────────────────────────────────────────────────
filesystem-mcp:
image: mcp/filesystem:latest
container_name: momo-mcp-filesystem
restart: unless-stopped
init: true
ports:
- "127.0.0.1:3004:3000"
environment:
- ALLOWED_PATHS=/data,/logs # 限制存取範圍
volumes:
- ./data:/data:ro # ⚠️ ro 唯讀,避免 LLM 改檔
- ./logs:/logs:ro
deploy:
resources:
limits:
memory: 128m
# ─────────────────────────────────────────────────────────────────────────────
# 與既有 momo-pro 共用 network讓 postgres-mcp 連 momo-db
# ─────────────────────────────────────────────────────────────────────────────
networks:
momo-shared:
external: true
name: momo-pro_default # 既有 docker-compose.yml 的 default network

View File

@@ -43,6 +43,8 @@ services:
image: ${MOMO_IMAGE:-registry.wooo.work/wooo/momo-pro-system}:${VERSION:-stable}
container_name: momo-pro-system
restart: unless-stopped
cpus: "2.0"
mem_limit: 2g
labels:
- "com.centurylinklabs.watchtower.enable=true"
ports:
@@ -59,8 +61,11 @@ services:
- ./config.py:/app/config.py:ro
- ./app.py:/app/app.py:ro
- ./auth.py:/app/auth.py:ro
- ./docker-compose.mcp.yml:/app/docker-compose.mcp.yml:ro
- ./gunicorn.conf.py:/app/gunicorn.conf.py:ro
- ./scheduler.py:/app/scheduler.py:ro
- ./scripts:/app/scripts:ro
- ./migrations:/app/migrations:ro
- ./services:/app/services:ro
- ./routes:/app/routes:ro
- ./database:/app/database:ro
@@ -74,8 +79,8 @@ services:
- FLASK_ENV=production
- PYTHONUNBUFFERED=1
- TZ=Asia/Taipei
- METABASE_URL=https://mo.wooo.work/metabase
- GRIST_URL=https://grist.wooo.work
- METABASE_URL=/metabase
- GRIST_URL=/grist
# 關閉登入驗證(開發/測試用,生產環境預設啟用登入)
- DISABLE_LOGIN=${DISABLE_LOGIN:-false}
# 資料庫設定: Docker 環境使用 PostgreSQL
@@ -85,8 +90,21 @@ services:
- POSTGRES_USER=${POSTGRES_USER:-momo}
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
- POSTGRES_DB=${POSTGRES_DB:-momo_analytics}
# Embedding 服務bge-m3 on Hermes (ADR-003),永遠走內網免 auth
- EMBEDDING_HOST=${EMBEDDING_HOST:-http://192.168.0.111:11434}
# Ollama 主機GCP-A → GCP-B → 111 自動備援ADR-028
- OLLAMA_HOST_PRIMARY=${OLLAMA_HOST_PRIMARY:-http://34.87.90.216:11434}
- OLLAMA_HOST_SECONDARY=${OLLAMA_HOST_SECONDARY:-http://34.21.145.224:11434}
- OLLAMA_HOST_FALLBACK=${OLLAMA_HOST_FALLBACK:-http://192.168.0.111:11434}
# EMBEDDING_HOST 若未設定,由 resolve_ollama_host() 自動決定(三主機級聯)
- EMBEDDING_HOST=${EMBEDDING_HOST:-}
# Gemini 只能作緊急備援;即使 .env 有 API key預設也不得產生付費出站。
- GEMINI_API_HARD_DISABLED=${GEMINI_API_HARD_DISABLED:-true}
- GEMINI_FALLBACK_ENABLED=${GEMINI_FALLBACK_ENABLED:-false}
# PPT 視覺 QA + 線上預覽:需要容器內 LibreOfficeDockerfile 安裝 libreoffice-impress
- PPT_VISION_ENABLED=${PPT_VISION_ENABLED:-true}
- PPT_VISION_MODEL=${PPT_VISION_MODEL:-minicpm-v:latest}
# ADR-020: Code Review 全自動修復主開關
# 預設 true任何 finding 一律觸發 AiderHeal可在 .env 顯式設 false 即時切斷
- CODE_REVIEW_AUTO_FIX_ENABLED=${CODE_REVIEW_AUTO_FIX_ENABLED:-true}
env_file:
- .env
healthcheck:
@@ -182,6 +200,8 @@ services:
image: ${MOMO_IMAGE:-registry.wooo.work/wooo/momo-pro-system}:${VERSION:-stable}
container_name: momo-scheduler
restart: unless-stopped
cpus: "2.0"
mem_limit: 2g
labels:
- "com.centurylinklabs.watchtower.enable=true"
init: true # 使用 tini 作為 init 進程,自動回收僵屍進程
@@ -204,8 +224,16 @@ services:
# H7 (2026-04-24): POSTGRES_* 改由 env_file: .env 唯一來源,移除 compose 層插值避免空值覆蓋
- USE_POSTGRESQL=true
- POSTGRES_PORT=5432
# Embedding 服務bge-m3 on Hermes (ADR-003),永遠走內網免 auth
- EMBEDDING_HOST=${EMBEDDING_HOST:-http://192.168.0.111:11434}
# Ollama 主機GCP-A → GCP-B → 111 自動備援ADR-028
- OLLAMA_HOST_PRIMARY=${OLLAMA_HOST_PRIMARY:-http://34.87.90.216:11434}
- OLLAMA_HOST_SECONDARY=${OLLAMA_HOST_SECONDARY:-http://34.21.145.224:11434}
- OLLAMA_HOST_FALLBACK=${OLLAMA_HOST_FALLBACK:-http://192.168.0.111:11434}
- EMBEDDING_HOST=${EMBEDDING_HOST:-}
# Gemini 只能作緊急備援;即使 .env 有 API key預設也不得產生付費出站。
- GEMINI_API_HARD_DISABLED=${GEMINI_API_HARD_DISABLED:-true}
- GEMINI_FALLBACK_ENABLED=${GEMINI_FALLBACK_ENABLED:-false}
- PPT_VISION_ENABLED=${PPT_VISION_ENABLED:-true}
- PPT_VISION_MODEL=${PPT_VISION_MODEL:-minicpm-v:latest}
env_file:
- .env
command: ["python", "run_scheduler.py"]
@@ -237,6 +265,8 @@ services:
image: ${MOMO_IMAGE:-registry.wooo.work/wooo/momo-pro-system}:${VERSION:-stable}
container_name: momo-telegram-bot
restart: unless-stopped
cpus: "0.5"
mem_limit: 512m
labels:
- "com.centurylinklabs.watchtower.enable=true"
init: true
@@ -257,7 +287,14 @@ services:
# H7 (2026-04-24): POSTGRES_* 改由 env_file: .env 唯一來源,移除 compose 層插值避免空值覆蓋
- USE_POSTGRESQL=true
- POSTGRES_PORT=5432
- EMBEDDING_HOST=${EMBEDDING_HOST:-http://192.168.0.111:11434}
# Ollama 主機GCP-A → GCP-B → 111 自動備援ADR-028
- OLLAMA_HOST_PRIMARY=${OLLAMA_HOST_PRIMARY:-http://34.87.90.216:11434}
- OLLAMA_HOST_SECONDARY=${OLLAMA_HOST_SECONDARY:-http://34.21.145.224:11434}
- OLLAMA_HOST_FALLBACK=${OLLAMA_HOST_FALLBACK:-http://192.168.0.111:11434}
- EMBEDDING_HOST=${EMBEDDING_HOST:-}
# Gemini 只能作緊急備援;即使 .env 有 API key預設也不得產生付費出站。
- GEMINI_API_HARD_DISABLED=${GEMINI_API_HARD_DISABLED:-true}
- GEMINI_FALLBACK_ENABLED=${GEMINI_FALLBACK_ENABLED:-false}
env_file:
- .env
command: ["python", "run_telegram_bot.py"]
@@ -654,6 +691,8 @@ services:
image: postgres:15-alpine
container_name: momo-postgres
restart: unless-stopped
cpus: "2.0"
mem_limit: 4g
# ADR-011: 生產主機使用獨立的 momo-db手動 docker run非 compose 管理)
# 此 service 僅供本地開發 / 一次性 migration 使用,預設不啟動。
# 啟用方式: docker compose --profile bundled-db up -d postgres
@@ -741,7 +780,7 @@ services:
- GRIST_SUPPORT_ANON=true
- GRIST_FORCE_LOGIN=false
- GRIST_HIDE_UI_ELEMENTS=helpCenter,billing,templates,multiSite,multiAccounts
- APP_HOME_URL=https://grist.wooo.work
- APP_HOME_URL=${GRIST_APP_HOME_URL:-https://mo.wooo.work/grist}
- TZ=Asia/Taipei
networks:
- momo-network

View File

@@ -11,7 +11,7 @@
|------|-----|
| URL | https://monitor.wooo.work/superset/ |
| 帳號 | admin |
| 密碼 | Wooo_Superset_2026 |
| 密碼 | <SUPERSET_ADMIN_PASSWORD> |
---

View File

@@ -11,7 +11,7 @@
|------|-----|
| URL | https://monitor.wooo.work/superset/ |
| 帳號 | admin |
| 密碼 | Wooo_Superset_2026 |
| 密碼 | <SUPERSET_ADMIN_PASSWORD> |
| 資料庫 | MOMO_UAT |
---

View File

@@ -66,7 +66,7 @@ chmod +x deploy.sh
| 內部 URL | `http://127.0.0.1:8088` |
| 外部 URL | `https://monitor.wooo.work/superset/` |
| 帳號 | `admin` |
| 密碼 | `Wooo_Superset_2026` |
| 密碼 | `<SUPERSET_ADMIN_PASSWORD>` |
## Nginx 配置

View File

@@ -92,7 +92,7 @@ deploy() {
echo "外部訪問: https://monitor.wooo.work/superset/"
echo ""
echo "登入帳號: admin"
echo "登入密碼: Wooo_Superset_2026"
echo "登入密碼: <SUPERSET_ADMIN_PASSWORD>"
echo ""
echo "下一步:"
echo " 1. 設定 Nginx 反向代理"

View File

@@ -64,7 +64,7 @@ services:
fi
done &&
superset db upgrade &&
superset fab create-admin --username admin --firstname Admin --lastname User --email admin@wooo.work --password Wooo_Superset_2026 || true &&
superset fab create-admin --username admin --firstname Admin --lastname User --email admin@wooo.work --password <SUPERSET_ADMIN_PASSWORD> || true &&
superset init &&
echo 'Superset 啟動中...' &&
gunicorn --bind 0.0.0.0:8088 --workers 4 --timeout 120 --access-logfile - 'superset.app:create_app()'

View File

@@ -1,25 +1,126 @@
# MOMO PRO — AI 競價情報模組 Single Source of Truth
# PChome 業績成長自動化作戰系統 — AI 競價情報模組 Single Source of Truth
> **最後更新**: 2026-05-01 (台北時間)
> **狀態**: 🟢 四 AI Agent 自動化閉環已落地 — EventRouter / AutoHeal / OpenClaw Memory / ElephantAlpha bridge / Prometheus metrics / Smoke Dashboard / Smoke Trend Management / Telegram Summary / Grafana provisioning / Prometheus scrape / CD Gunicorn 掛載具測試覆蓋
> **適用版本**: V10.22 Legacy 5888 入口清理版
> **最後更新**: 2026-06-18 (台北時間)
> **狀態**: 🟢 四 AI Agent 自動化閉環已落地LLM 路由紅線升級為 Ollama-first 三主機級聯PChome 後台業績匯入韌性已補強產品定位正名為「PChome 業績成長自動化作戰系統」外部市場來源正規化層、自動同步、作戰清單與價格參考表優先讀取、CSV 備援預檢、前台操作入口、高可見頁面繁中化守門、比價/作戰 UI 工作台化、GCP embedding 熔斷延後處理、110 proxy rescue 與 direct host health skip 已建立
> **適用版本**: V10.627
---
## 零、LLM 路由紅線2026-05-12
- 所有 AI Agent、LLM 推理與 embedding 預設必須走 Ollama 三主機級聯GCP-A `34.87.90.216:11434` → GCP-B `34.21.145.224:11434` → 111 `192.168.0.111:11434`
- `services/ollama_service.resolve_ollama_host()` 是主機解析契約;`OLLAMA_HOST``HERMES_URL``EMBEDDING_HOST``OLLAMA_API_BASE` 只接受 GCP-A / GCP-B / 111 或 110 的核准轉發端口。
- 188 直連 GCP-A / GCP-B timeout 時resolver 可先使用同順位 110 proxy rescueGCP-A direct → `192.168.0.110:11435` → GCP-B direct → `192.168.0.110:11436` → 111。proxy rescue 只是同一順位的可用入口,不代表 GCP direct host 已恢復。
- `OLLAMA_RESOLVE_HOST_HEALTH_SKIP_ENABLED=true`resolver 會讀最近 `host_health_probes`;若 direct GCP-A/GCP-B 在視窗內已被判定不健康,會直接略過該 direct endpoint先試同順位 proxy rescue避免每 120 秒 cache refresh 都等待 direct timeout。此 skip 只套用 direct GCP不套用 110 proxy。
- `config.OLLAMA_HOST``config.HERMES_URL``config.EMBEDDING_HOST` 只保留為舊 caller 相容常數import-time 不得 probe network也不得因 GCP-A/GCP-B 短暫不可用而 freeze 到 111。需要即時路由時一律呼叫 `get_ollama_host()``get_hermes_url()``get_embedding_host()``OllamaService`
- Gemini 只能作為 Ollama 主路徑失敗後的備援MCP Grounding、PPT/vision、週/月報、Code Review、EA HITL、複雜 SKU 升級等舊鎖定場景也必須先走 GCP-A → GCP-B → 111。
- 188 `192.168.0.188` 僅是 App / DB / scheduler / Telegram bot 容器宿主與 AutoHeal target不可作為 Ollama 節點。
- 通用 AI 文案、關鍵字、商品洞察與 Telegram Q&A 第一響應不得 Gemini-first。
- Hermes intent / analyst 路徑不得手刻 `/api/generate` 或只 resolve 單次 host必須走 `OllamaService`。預設 `HERMES_ALLOW_111_FALLBACK=false`,同一請求只跑 GCP-A → GCP-B兩台都失敗時回規則引擎或 DB 證據 fallback不把批量價格分析轉嫁到 111。救急時才可顯式設 true 允許 111 接手。
- NemoTron qwen3 dispatch 的 `/api/chat` tool-calling 路徑也必須同一請求最多嘗試三台 Ollama第一台失敗要 `mark_unhealthy()` 後再試下一台,最後才 fallback NIM。
- PPT vision、PPT 文案 final fallback、MCP 離線 final fallback 等特殊 Ollama 路徑也不得只打單一 host如需 `/api/generate`,一律透過 `OllamaService.generate()`
- Code Review pipeline 也必須 Ollama-firstHermes scan 與 OpenClaw assessment 都走 `OllamaService` 三主機 retryGemini telemetry 只能以 `code_review_openclaw_gemini` 出現,表示 Ollama/可選 Claude 備援都失敗後才啟用。
- Code Review Hermes scan 預設不呼叫 LLM改用 deterministic fast static scan避免部署後先卡三段 Ollama timeout需要 LLM 掃描時才以 `CODE_REVIEW_HERMES_LLM_SCAN_ENABLED=true` 啟用本地矩陣。
- Code Review Hermes LLM scan 啟用時才使用本地模型矩陣,且預設只跑 GCP-A `qwen2.5-coder:7b` → GCP-B `gemma3:4b``CODE_REVIEW_ALLOW_111_FALLBACK=true` 時才允許落到 111並由 `OllamaService` 降級到 `llama3.2:latest`。不啟用 Gemini 備援,本地掃描失敗時只回空 findings 並交由 OpenClaw 本地矩陣續跑。
- Code Review OpenClaw assessment 預設只跑 GCP-A → GCP-BGCP-A `qwen2.5-coder:7b`、GCP-B `gemma3:4b`primary timeout 預設 `15s`、secondary timeout 預設 `60s`,讓 A 掛時快速讓位給 B且 B 有足夠時間完成審查 prompt。111 是最後救急節點,但部署後重分析預設不打 111只有 `CODE_REVIEW_ALLOW_111_FALLBACK=true` 才允許 111 接手,並降級到 `llama3.2:latest`。Code Review 的 Ollama `keep_alive` 預設為 `5m`,不得再用 `24h` 長駐 runner 壓住 GCP-B/111。GCP-A/GCP-B 都失敗且 Claude/Gemini 未顯式開啟時,必須回 deterministic 本地降級摘要,不呼叫 Gemini、不落 111、不走其他雲端模型。
- Embedding / semantic RAG 背景任務預設只跑 GCP-A → GCP-B`OpenClawLearningService` embedding worker 與 `RAGService` 查詢 embedding 呼叫 `OllamaService.generate_embedding(..., allow_111_fallback=False)`111 只可作人工明確指定的救急路徑,不承接 `bge-m3` 背景批次。`OLLAMA_EMBED_TIMEOUT` / `OLLAMA_EMBED_MAX_TIMEOUT` 預設 `30s``OLLAMA_EMBED_KEEP_ALIVE=1m``OLLAMA_EMBED_MAX_CHARS=4000`;此上限依 GCP-B `bge-m3` 實測 623s 波動調整,避免慢但成功的 embedding 被 15s cap 誤殺。
- `allow_111_fallback=False` 時,若 resolver 因 unhealthy cache 回傳 111不得直接結束 embedding必須強制改試尚未嘗試的 GCP-A / GCP-B避免正式 log 出現 `tried=[]` 或只試單台 GCP-B。
- `allow_111_fallback=False` 且 GCP-A / GCP-B 皆失敗時,背景 embedding 會開啟短暫 GCP failure circuit預設 60 秒),期間不重複打兩台 GCP、不落 111避免 worker 與 log 被連續失敗拖慢GCP 恢復後會自然再試。
- 背景 embedding 的 GCP-only 熔斷屬於可降級背景能力,應記錄為明確 WARNING 與 circuit 狀態,不應每次污染 ERROR 通道;真正允許三主機 fallback 的同步 embedding 全失敗仍保留 ERROR。
- OpenClaw embedding worker 遇到 GCP-only failure circuit 時,必須把已 claim 任務退回 `pending` 並延後處理,不得扣 `attempts`、不得把同批任務刷成 `failed`;熔斷期間也不得繼續 claim 新任務。
- Scheduler host health probe 不只看 `/api/tags`GCP-A / GCP-B 節點必須再通過 `bge-m3` `/api/embed` 實作探針,才算 healthy。探針 timeout 預設 30s111 預設不納入這個背景 embedding 探針,避免監測任務把 fallback Mac 載入 `bge-m3`
- 背景 embedding 會讀取最近 `host_health_probes` runtime 結果;若 GCP-A / GCP-B 在 `OLLAMA_EMBED_HOST_HEALTH_SKIP_WINDOW_MINUTES=20` 視窗內已被標為 unhealthy`OllamaService.generate_embedding(..., allow_111_fallback=False)` 會先跳過該節點並開啟短暫 GCP circuit不再等待 30 秒 timeout也仍不落 111。此功能由 `OLLAMA_EMBED_HOST_HEALTH_SKIP_ENABLED=true` 控制DB 讀取失敗時 fail-open 回到原本網路 retry。
- BGE-M3 一致性檢查是監測任務,不是 fallback 壓測;預設只比對 GCP-A / GCP-B。111 Mac fallback 只有 `EMBED_CONSISTENCY_INCLUDE_111=true` 時才納入,避免每週背景檢查把 `bge-m3` 載入 111。
- OpenClaw Telegram Q&A 主路徑也不得綁單一 host`_call_qwen3_qa()` 必須透過 `OllamaService` 跑 GCP-A → GCP-B → 111並把實際落點寫入 `ai_calls.provider`
- OpenClaw Telegram 圖片商品辨識也必須 Ollama-first`_identify_product_name_with_ollama_vision()` 透過 `OllamaService` 嘗試 GCP-A → GCP-B → 111Gemini 只允許以 `openclaw_bot_image_gemini` caller 作為失敗後備援。
- OpenClaw 週報、月報、Meta analysis、日報洞察、Telegram PPT 分析與 MCP fallback 也必須 Ollama-firstGemini caller 只能帶 `_gemini_fallback` 或明確 fallback caller 語意,且不得先於 Ollama/NIM 被呼叫。OpenClaw strategy 的 Ollama `keep_alive` 預設為 `5m`,避免報告型任務把 GCP-B/111 runner 長駐 24h。
- OpenClaw 週報、月報、Meta analysis、日報洞察與每日報告的 Gemini/NIM 備援 caller 必須登錄在 caller registry、AI 觀測台 agent group 與 Telegram 狀態統計,避免 fallback 用量被歸類為未知或漏算。
- `ai_calls.provider='ollama_other'` 只允許作為 unresolved/unknown Ollama telemetry bucket例如全 host 失敗、尚未選定實際 GCP-A/GCP-B/111 host 或舊 caller 未帶 host不得把 `ollama_other` 當成實際路由目標或新增非核准 Ollama host。
- GCP-B 若缺 caller 指定的 coder/large 模型,`OllamaService` 必須先在 GCP-B 改用 `OLLAMA_SECONDARY_MODEL_FALLBACK`(預設 `gemma3:4b`),不可因 model 404 把整台 GCP-B 標成 unhealthy 後直接推到 111真正 timeout / HTTP 5xx 才標 host unhealthy。
- Gemini API 出站有第二道 kill switch`GEMINI_FALLBACK_ENABLED` 預設為 `false`。即使 `GEMINI_API_KEY` 存在,通用 AI fallback、OpenClaw 報告/QA/PPT/圖片、MCP Grounding 與 Code Review L3 都不得呼叫 Gemini只有操作員明確設為 `true`Gemini 才能作緊急備援。
- `docker-compose.yml``momo-app``scheduler``telegram-bot` 必須明確設定 `GEMINI_API_HARD_DISABLED=${GEMINI_API_HARD_DISABLED:-true}``GEMINI_FALLBACK_ENABLED=${GEMINI_FALLBACK_ENABLED:-false}``.env` 可保留 `GEMINI_API_KEY`,但不得因 key 存在就讓核心容器產生 Gemini 付費出站。
- OpenClaw 日/週/月/Meta 等敘事報告屬長任務Ollama 只能走 GCP-A → GCP-B不得使用 111 final fallback 承接長文生成。GCP 兩台都不可用時,應走既有 Gemini hard-disabled guard 後的 NIM / deterministic degraded path避免 111 被非即時分析壓高負載。
- Gemini 不可被任何狀態面板或 router 推薦為主提供者:`AIProviderService._get_recommended_provider()` 不得回傳 `gemini`,只能顯示為 fallback 狀態;`llm_model_router``ea_engine` 若收到 `gemini-*` default 必須改回 `hermes3:latest`,需要深推理時才升本地 `deepseek-r1:14b`
- ElephantAlpha prompt / agent registry 不得再把 OpenClaw 描述為 Gemini 主模型OpenClaw 是 `qwen2.5-coder:7b` / `qwen3:14b` Ollama-first 策略師Gemini 僅能在 guard 顯式解鎖後作 emergency fallback。
- 111 `192.168.0.111` 只是最後一道 Mac fallback不承接 7B+、vision、long-context 模型長駐;`OllamaService.generate()` 落到 111 時會將 `qwen3``deepseek-r1``hermes3``qwen2.5*``gemma3``llava``minicpm-v` 與 7B+ 模型依 `OLLAMA_111_MODEL_DOWNGRADE_PATTERNS` 降級到 `OLLAMA_111_MODEL_FALLBACK=llama3.2:latest`,並以 `OLLAMA_111_KEEP_ALIVE=5m``OLLAMA_111_MAX_TIMEOUT=20``OLLAMA_111_NUM_CTX=4096``OLLAMA_111_NUM_PREDICT=512` 封頂。OpenClaw 報告型路徑的業務 keep-alive 預設 `5m`Code Review 以 `CODE_REVIEW_ALLOW_111_FALLBACK=false`、Hermes 以 `HERMES_ALLOW_111_FALLBACK=false` 預設跳過 111避免 16GB RAM 主機與 GCP-B 被長駐 runner、長輸出與 24h keep-alive 壓到高 load。
- Scheduler 每 15 分鐘執行 `run_ollama_111_usage_guard_check()`,只讀 `ai_calls` 統計最近視窗的 GCP-A / GCP-B / 111 呼叫量;預設 60 分鐘內 Ollama 呼叫至少 20 次、111 至少 3 次且占比 >= 5% 才推 Telegram。這是觀測護欄不改路由、不寫 DB、不自動重啟服務。
- `OllamaService` 對 111 final fallback 有 circuit breaker預設最近 60 分鐘 Ollama 呼叫至少 20 次、111 至少 5 次且占比 >= 5% 時,短暫跳過 111`OLLAMA_111_CIRCUIT_CACHE_SEC=60`),避免 111 在已偏高時繼續承接長任務DB 觀測失敗時 fail-open不讓主要 GCP-A/GCP-B 路由被觀測層中斷。
- 111 的 LAN 入口必須經 `scripts/ops/ollama111_allow_proxy.py` allowlist proxy真實 Ollama 綁 `127.0.0.1:11434`proxy 綁 `192.168.0.111:11434`,預設只允許 111 本機與 188 生產宿主110 / 121 / 其他 LAN client 不能直接打 111避免跨專案 CI 或 VM 繞過 momo-pro router 載入 7B+ runner。111 上以 `scripts/ops/install_ollama111_allow_proxy.sh` 安裝 user LaunchAgent安裝器會把 proxy script 複製到 `~/.local/share/momo-pro-system/ollama111_allow_proxy.py`,讓 LaunchAgent 不依賴 iCloud repo 掛載路徑,並讓 proxy 與 `OLLAMA_HOST=127.0.0.1:11434` 在登入/重啟後自動恢復。拒絕日誌以 `OLLAMA111_PROXY_REJECT_LOG_DEDUP_SEC=60` 去重,避免 121 這類旁路探測刷爆 111 磁碟日誌。
- ElephantAlpha 的 `price_drop_alert` / `market_opportunity` Telegram HITL 告警必須把同款證據獨立呈現,至少包含 `match_type``price_basis``alert_tier``match_score`;沒有高信心同款與總價可比證據時,不得把 PChome/MOMO 價差寫成可直接跟價建議。
## 零之零、產品定位正名2026-06-15
- 本專案的營運定位正名為「PChome 業績成長自動化作戰系統」。
- 主要目標是提升 PChome 銷售業績MOMO 是目前已接入的外部價格參考來源,不再把 PChome 視為附屬競品語意。
- 使用者可見 UI、Telegram 與報表文案必須白話、可行動,優先使用「商品對應」「可直接比價」「待補對應」「放大價格優勢」「檢查售價與活動」等營運語言,避免把 `identity_v2``match_score``candidate queue` 等工程詞直接丟給使用者。
- `services/pchome_revenue_growth_service.py` 是第一版只讀作戰清單:讀 PChome 後台業績與已驗證 MOMO 外部價格參考,輸出 `/api/ai/pchome-growth/opportunities`。此服務不呼叫 LLM、不抓外站、不寫 DB。
- 2026-06-15 只讀盤點確認:`daily_sales_snapshot."商品ID"``competitor_prices.competitor_product_id` 在正式資料中直接重疊為 0。因此第一版作戰清單不得硬接兩邊 ID若沒有可驗證對應只能輸出「先補商品對應」任務。
- 蝦皮與酷澎暫停接入,不進作戰清單、不發告警;後續只可透過 official API / provider API / manual CSV 進 `external_offers` 類正規化層,並清楚標示資料品質。
- V10.607 新增 `external_market_sources` / `external_offers` 正規化層與 `/api/ai/pchome-growth/source-contract` 只讀 API。MOMO 先以既有比價快取橋接進來源狀態;蝦皮與酷澎只保留 official API、provider API、manual CSV contract預設暫停且不進告警。
- V10.608 新增 `/api/ai/pchome-growth/external-offers/csv-dry-run` 與 AI 情報頁「外部報價預檢」。CSV 預檢只讀、不寫 DB逐列回報「可使用」「需人工確認」「不能使用」並支援中文表頭避免格式小錯造成整批匯入失敗。
- V10.609 明確把外部報價主路徑改為自動化:`run_external_offer_sync_task` 每 4 小時將已確認同款的既有比價快取同步進 `external_offers`。CSV 只保留為 API / crawler / provider 失敗時的備援預檢入口,不是日常營運主流程。
- V10.610 起 `/api/ai/pchome-growth/opportunities` 優先讀取 `external_offers` 的自動同步資料;只有新資料層缺資料時才 fallback 舊 `competitor_prices`。API stats 會回傳資料來源計數,方便確認作戰清單是否已走新資料層。
- V10.611 起 `/ai_intelligence` 是營運使用者主入口V10.617 已將舊「今日作戰入口 / 外部報價預檢」改為「今日重點總覽 / 備援資料檢查」,主流程不得再把人工 CSV 放在前段。
- V10.612 起 `/api/ai/icaim/dashboard` 的「MOMO 外部價格參考」表格也優先讀 `external_offers`,缺資料才 fallback `competitor_prices`;價差與風險改採 PChome 視角,正數代表 PChome 比 MOMO 外部參考價高。
- V10.613 起高可見前台頁面必須以繁體中文呈現程式碼審查、AI 自動化健康檢查、PPT 產線與商品看板操作標籤不得使用英文工程標題或簡體字;測試需防止頁面文案退回英文。
- V10.614 起部署監控、基礎設施生命線與 PPT 產線狀態也納入繁中守門:前台不得顯示 `Dashboard``Pipeline``Runtime` 等工程詞,動態階段需轉成「測試 / 建置 / 部署」。
- V10.615 起 AI 智慧推薦頁必須把 Ollama 顯示為「Ollama 主路徑」Gemini 只能顯示為「Gemini 備援」且手動選項停用;使用者可見錯誤與搜尋流程不得出現 `Web Search``Token:`、半形英文冒號等工程文案。
- V10.616 起主商品看板 `/` 的統計與補強區塊也納入繁中守門:不得顯示 `ACTIVE``PICK COUNT``AVG CONFIDENCE``EVIDENCE GAP``PCHOME MATCH BACKFILL` 等工程標籤畫面需使用「有效商品」「挑品數」「平均信心」「待補證據」「PChome 比價補強」等白話營運文案。
- V10.617 起 `/ai_intelligence` 必須採「先給下一步」的作戰導向 UI首屏需先回答「今天先做什麼」再呈現商品處理進度、外部價格來源與操作捷徑今日處理清單需用表格呈現優先級、建議動作、商品、近 7 天業績、比價結果、資料可信度與下一步MOMO 外部價格參考需顯示價格風險分佈,且表格需以 PChome 價格優先明確顯示「PChome 貴 / PChome 便宜」與可信度,不得只用大段文字說明使用方式。
- V10.618 起 `/price_comparison` 也必須採「先給下一步」的比價決策 UI首屏需顯示目前卡在哪一步、PChome / MOMO 資料準備狀態與下一個按鈕;比價結果需先呈現「需檢查價格 / 可主推曝光 / 價格接近」分佈,再用表格列出每筆商品的下一步,不得只呈現 Step 流程或原始價差表。
- V10.619 起 MOMO 比價候選來源新增「PChome 商品導向搜尋」:當比價 API 已有 PChome 商品但缺 MOMO 清單時,必須用每筆 PChome 商品名稱產生精準搜尋詞反查 MOMO保留品牌、品名、容量與組合線索新版 MOMO 搜尋頁需解析 Next.js `goodsInfoList` payload。此路徑只擴大候選池不放寬同款 matcher 門檻。
- V10.620 起 `unit_comparable` 不再一律丟人工確認:若 `build_unit_price_comparison()` 可產生明確容量/數量、MOMO 單位價、PChome 單位價與差距百分比,候選需標為「自動單位價比較」並回傳 `auto_compare_type=unit_price`。此類候選可自動呈現價格壓力,但不得混入舊總價同款比價表,也不得直接寫入正式價差或自動改價;無法產生單位證據時才維持「需人工確認」。
- V10.621 起 `/price_comparison` 的「自動找 MOMO 候選」會把可直接總價比價與自動單位價候選同步到 `external_offers``ingestion_method='targeted_momo_search'`,人工確認候選不得寫入。`external_offers.raw_payload_json.price_basis='unit_price'` 時,作戰清單必須使用 `unit_price_comparison` 的 MOMO / PChome 單位價與 `unit_gap_pct` 判斷價格壓力;不得把 MOMO 組合總價與 PChome 單品總價直接相減。此同步只影響外部價格參考與作戰清單,不寫 `competitor_prices`,也不自動改價。
- V10.622 起任何 `external_offers` 自動同步成功寫入後,必須呼叫 `mark_pchome_growth_cache_stale()` 寫入共享 cache epoch`/api/ai/pchome-growth/opportunities` 讀快取前必須比對 `get_pchome_growth_cache_epoch()`。這是跨 Gunicorn worker 的可見性保護,避免自動候選已進外部價格參考,但 AI 情報頁仍回 120 秒舊作戰清單。
- V10.623 起 `/price_comparison``/ai_intelligence` 不得只靠大段文字說明流程:比價頁第一屏必須有主 KPI、目前卡點、四步流程與結果決策摘要作戰頁第一屏必須有今日任務、可立即處理、待補比價與最新業績日。所有狀態都要由實際 API/前端狀態驅動,讓使用者一眼知道下一步要按哪個動作。
- V10.638 起 PChome 導向 MOMO 補抓會把「找到但不能自動比價」的候選以 `match_status='needs_review'``data_quality_status='needs_review'` 保存到 `external_offers`;這些候選不得進價格壓力判斷,也不得發告警,但 `/api/ai/pchome-growth/opportunities` 可回傳待確認候選數,讓 UI 顯示「已有候選待確認」而不是只顯示無法比價。
- V10.639 起待確認候選排序必須容忍缺少單位數量;沒有 `momo_total_quantity` / `competitor_total_quantity` 時仍可保存為 `needs_review`,不得中斷 PChome 導向 MOMO 回填。
- V10.640 起 `/ai_intelligence` 必須提供 MOMO 待確認候選操作佇列;使用者可直接確認同款或排除候選。確認後 `external_offers` 會轉為 `verified/verified` 並進入作戰清單,排除後轉為 `rejected/rejected`,兩者都必須清掉 PChome 成長作戰清單快取。
- V10.641 起 `/ai_intelligence` 的摘要數字不可只是靜態文字;第一屏 KPI、商品處理進度、待確認數字都必須可點擊並導向對應明細。今日清單若已有 MOMO 待確認候選,下一步必須顯示「確認候選」並跳到候選面板,不得再只顯示「補齊比價」。
- V10.642 起 `/ai_intelligence` 的摘要卡與商品處理數字不可只跳到大區塊;點擊後必須開啟商品明細面板,列出商品名稱、分類、近 7 天業績、業績變化、MOMO 比價狀態與下一步按鈕。明細需至少支援全部、價格壓力、價格優勢、待確認、缺比價與有外部價切換;外部價格風險分佈也必須能一鍵篩選下方表格。
- V10.643 起 `/ai_intelligence` 的商品明細上方必須提供「商品策略分流」視覺摘要,至少包含價格壓力、價格優勢、待確認、缺比價四類;每一類需顯示件數、近 7 天業績與比例條,且可點擊切換明細。舊 KPI 卡也不得是靜態數字,需可導向全部商品、可處理商品、高風險比價或處理紀錄。
- V10.644 起 `/ai_intelligence` 的商品明細列不得只用句子描述比價;每列必須顯示 PChome 價格、MOMO 參考價、差距、可信度四格價格證據,並保留下一步按鈕。單位價候選需顯示單位價與單位,候選待確認或缺資料則以「待補 / 候選待確認」呈現,不得捏造價格。
- V10.645 起 `/ai_intelligence` 的商品明細分流切換後,必須顯示「這類商品怎麼處理」的行動摘要,包含件數、近 7 天業績、平均可信度、最大價差、代表商品與主按鈕;使用者不得只能看到商品列表而不知道下一步。
- V10.646 起 `/ai_intelligence` 的商品明細必須提供搜尋與排序;搜尋至少涵蓋商品、分類、商品編號與 MOMO 候選資訊,排序至少支援優先級、近 7 天業績、價差、下滑幅度與可信度。搜尋/排序後的行動摘要與明細列表必須使用同一批結果。
- V10.647 起 `/ai_intelligence` 的商品明細每一筆都必須能打開單品作戰詳情,詳情需顯示商品、建議動作、近 7 天業績、業績變化、PChome/MOMO 價格證據、價差、可信度、判斷原因與下一步操作;不得只讓使用者看一排文字後自行猜測。
- V10.648 起 `/ai_intelligence` 的商品明細上方必須提供分類策略看板,把商品依分類彙總成可點擊的數據條列;每列至少顯示分類、近 7 天業績、商品數、價格壓力、價格優勢、缺比價、待確認與建議下一步。點擊分類後必須切到該分類商品明細。
- V10.649 起 `/ai_intelligence` 必須提供銷售策略建議看板,把商品分成價格防守、主推曝光、組合/單位價、資料補齊等營運路徑;每張策略卡需顯示件數、近 7 天業績、代表商品與可點擊下一步,點擊後必須切到對應商品明細。
- V10.650 起 `/ai_intelligence` 必須提供「今日策略動作」清單,從作戰商品中挑出前 5 件具體行動;每列需顯示處理順序、動作、商品、近 7 天業績、原因與可點擊的詳情/處理入口,避免使用者只看到分類與策略後仍不知道下一步要做哪一件商品。
- V10.651 起從「今日策略動作」或其他非明細列入口打開單品作戰詳情時,商品明細列表中的對應商品仍必須標示為目前選取;使用者需能看出詳情與明細列的關聯。
- V10.652 起正式首頁 `/` 必須導向「PChome 業績成長自動化作戰系統」,舊商品看板僅保留在 `/dashboard``/product-dashboard`;「今日策略動作」必須放在首屏任務摘要後方,不能只藏在商品明細區;每列必須直接顯示價格證據,至少包含 PChome、MOMO、差距與可信度四格。候選待確認或缺資料時需以待確認/待補呈現,不得要求使用者先打開詳情才知道判斷依據。
## 零之一、12 Agent 決策信封2026-05-24
- 12 角色分工不作為 12 個常駐模型;在產品層統一收斂成 `decision_envelope`,由 Hermes / NemoTron / OpenClaw / ElephantAlpha 與人工審核、PPT QA、競品 review queue 共用。
- `decision_envelope` 必須至少能表達:`decision_type``severity``evidence[]``recommended_action``expected_impact``confidence``guardrails``trace`
- `guardrails.can_auto_execute=false` 是預設價格調整、正式比價覆寫、PPT 發送與修復執行都必須遵守 HITL 或既有 service guard不得因 Agent 信心高就繞過 matcher / feeder / review service。
- 證據不足時不得輸出空泛效益預測;必須標記 `data_quality=missing|partial|stale`,並把建議行動降級成 `human_review``needs_research``silence_alert`
- Telegram `triaged_alert()` 已支援渲染 `decision_envelope`,讓告警固定呈現嚴重度、證據、建議行動、預期影響、信心度與追蹤 ID後續觀測台與 PPT 也應共用同一份欄位語意。
- NemoTron `price_alert` / `human_review` 派發會把同款證據、價差、七日銷量變化、營收流失、HITL 邊界與資料品質寫入同一份 `decision_envelope`,並同步放入 EventRouter event 與 KM metadata12 Agent 後續只能沿用此信封補充分析,不得繞過 matcher / feeder / review service 直接改價或覆寫比價資料。
- EventRouter / Telegram 的 HITL callback 必須優先使用 `decision_envelope.decision_id` 作為事件追蹤 ID若上游未帶 `event.id``triaged_alert()` 仍會用 `decision_id` 產生 `momo:eig:*` callback避免價格決策審核落成 `unknown`。所有 `momo:eig:*` callback 必須以 UTF-8 byte-safe 截斷,確保 `callback_data` 不超過 Telegram 64-byte 限制。
- 競品比價相關的 Agent 建議只能讀 `competitor_match_attempts` / review queue / `competitor_prices` 的既有證據;不得直接寫 `competitor_prices` 或覆蓋 `_should_upsert_competitor_price()` 的保護規則。
- 已帶 `decision_envelope` 的價格/覆核事件必須由 EventRouter 直接渲染證據模板,不再進 L1/L2 AI 重新摘要Telegram 決策信封需顯示標的 SKU、商品名稱、PChome 候選、evidence、guardrails 與 HITL 動作,避免已有實證的比價告警被二次生成文字稀釋或造成額外模型成本。
- PChome 覆核隊列本身也必須輸出 `decision_envelope``fetch_competitor_review_queue()``fetch_competitor_review_queue_page()``/api/pchome-review/queue` 的每筆候選需帶相同的 `subject``evidence``recommended_action``expected_impact``guardrails`,供 Dashboard、Agent、Telegram 與 PPT 共用;任何下游不得另寫一套比價狀態翻譯或繞過 HITL guardrails。
- Dashboard 覆核卡與 `/api/export/excel/pchome-review` 也必須顯示/匯出 `decision_envelope` 的等級、資料品質、建議代碼、HITL、trace 與 `can_auto_execute=false` 邊界;操作員離開系統畫面或下載 Excel 後,仍要看得到「不可自動寫正式價差」的 guardrails。
- OpenClaw 週報/日報/月報與 competitor PPT 不得再各自重算或翻譯 PChome 覆核狀態;必須透過 `competitor_intel_repository.summarize_review_decision_envelopes()` 讀取同一份 `decision_envelope` 摘要,並在 prompt / data_summary / KPI slide 保留 HITL 與 `can_auto_execute=false` 邊界。
- Webcrumbs / Shared UI host data 也必須透過 `summarize_review_decision_envelopes()` 輸出 `reviewDecisionBrief`,並在 metadata 保留 review queue、HITL、auto-execute-blocked、`decision_support_rate``catalog_comparable_count` 與 catalog review lane counts不得另寫一套 PChome 覆核摘要或在前端 runtime 重新推論價格行動。
- ElephantAlpha 的 `resource_optimization` 與低信心 `ea_escalation` 也必須輸出 `decision_envelope`:資源壓力信封只能使用 `action_plans`、CPU 實測、hygiene 結果與 insight/action trace不得加入 LLM 預測效益;`triaged_alert()``ea_escalation` 亦需渲染信封並以 `decision_id` 作為 callback 追蹤 ID。
## 一、四 AI Agent 路由架構
```
SQL漏斗(~300筆)
[Hermes 3 8B] — 分析師 (本地 Ollama, 零成本)
模型: hermes3:latest @ 192.168.0.111:11434
[Hermes 3 8B] — 分析師 (Ollama 三主機級聯, 零成本)
模型: hermes3:latest @ GCP-A → GCP-B → 111
任務: 競價威脅分類 → TOP 20 HIGH/MED/LOW
[NemoTron NIM] — 派發器 (雲端, 免費配額)
模型: meta/llama-3.1-8b-instruct @ NVIDIA NIM
[NemoTron / qwen3] — 派發器
主路徑: qwen3:14b @ GCP-A/GCP-B落到 111 時自動降級 llama3.2
備援: NVIDIA NIM meta/llama-3.1-8b-instruct
任務: Tool Calling → Telegram 告警 / DB 寫入
[OpenClaw / Gemini] — 策略師 (費用審批制)
[OpenClaw] — 策略師 (Ollama-firstGemini 僅備援 / 鎖定場景)
任務: 週策略報告、洞察報告、L3 HITL 建議
[ElephantAlpha] — 編排者 (L3 Orchestrator)
@@ -36,14 +137,34 @@ SQL漏斗(~300筆)
- 後台入口:`POST /api/ai/product-picks/generate``/ai_intelligence` 可手動產生清單。
- 配對來源仍以 PChome crawler 真實搜尋結果為準;無競品資料時不生成挑品。
- 比對覆蓋率補強入口:`POST /api/ai/pchome-match/backfill`,優先補抓仍無有效 PChome 配對的高價 ACTIVE 商品,完成後自動重算 AI 挑品清單。
- 過期價格刷新入口:`POST /api/ai/pchome-match/refresh-stale`,只針對已建立 `identity_v2``expires_at` 過期的 PChome product_id 執行 `run_expired_identity_refresh()`;不得跑 fresh search recovery不得呼叫 LLM完成後重算 AI 挑品並清除 Dashboard / competitor intel cache。
- 過期 identity 搜尋救援入口:`POST /api/ai/pchome-match/recover-stale` 預設必須關閉主操作入口,僅保留只讀 preview正式 smoke 顯示小批次成功率不足且耗時偏高時,不得在 Dashboard 顯示日常操作按鈕。若需操作員手動執行,必須先明確設定 `PCHOME_STALE_RECOVERY_ENABLED=true`,再對已過期 `identity_v2` 先走既有 PChome product_id refresh只有舊 ID 查無商品或重評低於門檻時,才允許受控 fresh search recovery。救援隊列必須先排除 variant、catalog、commercial condition、count、bundle、unit-price 與任選 / 多款 / 香味 / 色號 / 即期 / 融燭燈 / 香氛蠟燭 / `+` / `xN` / `*N` / 具名香味或膚感版本等高風險名稱訊號。這條路徑可抓 PChome但不得呼叫 LLM正式寫入仍必須通過 matcher、hard veto、auto price write safety 與 overwrite protection。
- 補抓狀態入口:`GET /api/ai/pchome-match/backfill/status` 除背景任務狀態外,必須回傳 read-only coverage snapshot`active_with_price` / `valid_matches` / `match_rate` / `fresh_matches` / `fresh_match_rate` / `decision_ready_matches` / `decision_ready_rate` / `stale_matches` / `pending` / `actionable_review_count`,供 Dashboard 顯示目前該刷新過期價格或補抓未搜尋商品;此端點不寫 DB、不呼叫 LLM、不抓外站。`match_rate` 是身份覆蓋率,`fresh_match_rate` 是已配對 identity 內的新鮮比例,`decision_ready_rate` 才是可直接進入決策、圖表與簡報的 ACTIVE 商品比價覆蓋率。
- 排程閉環:`run_pchome_match_backfill_task` 每日 10:30 執行,補抓 PChome 待比對商品、寫入歷史價格,再重算 `strategy='product_pick'` 清單。
- 商品看板第一屏:`/` 的 V2 看板直接以 `products``price_records``competitor_prices``ai_price_recommendations` 顯示比對覆蓋率、PChome 優勢、MOMO 威脅、AI 挑品與待比對優先清單;`filter=ai_picks` 可查看 50 品 AI 挑品列表,並在列表上方顯示平均信心、平均價差、最大價差與估算總價差空間,列表列內顯示 AI 排名與建議理由,且可透過 `/api/export/excel/ai-picks` 匯出 50 品 Excel 操作清單。商品看板深度快取同時寫入 `data/dashboard_full_cache.pkl`,供多個 Gunicorn worker 共用,避免部署後各 worker 重複重建 7,000+ 商品統計造成開頁變慢;所有資料異動與 AI 挑品重算都透過 `clear_dashboard_cache()` 同步清除記憶體與共享快取,手動重算 API 會立即預熱商品看板快取,避免第一位使用者承擔重建成本
- PChome / MOMO 競價摘要出口 `services/competitor_intel_repository.py` 使用 30 分鐘共享快取(`COMPETITOR_INTEL_CACHE_TTL_SECONDS` 可調),避免 `/growth_analysis``/daily_sales`、PPT/AI 報表每次請求重跑昂貴覆蓋率與價差趨勢查詢;`run_competitor_price_feeder_task` 與 PChome backfill 完成後會主動清除快取。快取只包摘要輸出,不改 matcher 的高信心門檻與 identity_v2 準確性規則
- 商品看板第一屏:`/` 的 V2 看板直接以 `products``price_records``competitor_prices``competitor_match_attempts``competitor_match_reviews``ai_price_recommendations` 顯示比對覆蓋率、PChome 優勢、MOMO 威脅、AI 挑品、待比對優先清單與 PChome 覆核隊列;`filter=ai_picks` 可查看 50 品 AI 挑品列表,`filter=pchome_review` 可直接查看需人工處理的比價覆核 SKU並以 DB 分頁支援 search/category/status 後的完整隊列,不得只截前 50 筆。覆核狀態篩選必須至少包含全部、需單位價、已排除、低信心、價格過期、找不到同款與人工閉環,讓人工可依 matcher 診斷類型分批處理。列內顯示候選 PChome 商品、候選價、match score、單位價換算摘要、人工動作與 matcher 診斷原因標籤(品牌不符、商品線不符、容量差異、組合差異、需單位價、價差極端等),不得只顯示籠統「待比對」。`/api/export/excel/pchome-review` 必須匯出同一套覆核隊列、人工處置、候選 PChome、單位價比較與原始診斷讓人工覆核、簡報與後續 AI 分析共用同一份證據。`/api/pchome-review/<sku>/decision` 是人工閉環入口:`accept_identity` 才可把候選寫入 `competitor_prices``competitor_price_history` 並打上 `manual_review/manual_accept/identity_v2``reject_identity``unit_price_required``needs_research` 只寫 `competitor_match_reviews` 並追加 manual attempt不得把不同販售組合或否決候選灌入正式價差。PChome feeder 後續搜尋同一候選時必須讀取 `competitor_match_reviews`:已否決候選寫 `manual_rejected` 並跳過正式寫入,且必須繼續評估下一個候選,不能讓已否決候選長期阻塞同 SKU已標記單位價候選寫 `manual_unit_price_required`;已要求補搜尋候選寫 `manual_needs_research` 並停留在覆核隊列;已採用候選可保守補到最低門檻並保留 `manual_review/manual_accept` 標籤。搜尋候選池只有強同款分數達 `0.90` 才可提前停止,避免 0.76 灰區候選卡掉後續更精準搜尋詞。人工 `reject_identity``unit_price_required``needs_research` 若命中當前正式候選,必須將同候選 `competitor_prices` 過期,不得繼續顯示正式總價差。商品列表必須將 `manual_rejected``manual_unit_price_required``manual_needs_research` 顯示為明確人工閉環狀態,不可回落成籠統「待比對」。`fetch_competitor_coverage()` 必須輸出人工採用、人工否決、人工單位價與採用率daily/growth/PPT 共用 payload 必須顯示人工閉環成效,避免只呈現待審數。商品看板深度快取同時寫入 `data/dashboard_full_cache.pkl`,供多個 Gunicorn worker 共用,避免部署後各 worker 重複重建 7,000+ 商品統計造成開頁變慢;所有資料異動與 AI 挑品重算都透過 `clear_dashboard_cache()` 同步清除記憶體與共享快取,手動重算 API 會立即預熱商品看板快取,避免第一位使用者承擔重建成本。
- PChome re-score 回收線:`rescore_accepted_current` 只能表示最新版 matcher 判定「值得人工覆核身份」,不可直接寫入正式 `competitor_prices``no_match``price_basis=none``alert_tier=suppress``variant_selection_review` 不得進入此隊列。`fetch_competitor_coverage()` 必須輸出 `rescore_accepted_count`Dashboard、daily/growth 與 OpenClaw 競品摘要都要把「重算待人工覆核」獨立呈現,避免和一般低信心/單位價覆核混在一起。
- PChome 低信心操作分流Dashboard 與 read-only `/api/pchome-review/queue` 必須把近門檻可救、證據不足、低信心舊候選拆成 `recoverable_low_score``true_low_confidence``legacy_low_score` 三個可篩選桶;廣義 `low_score` 僅作 repository/export 相容查詢,不可在 UI 中冒充單一操作分流。
- PChome coverage 的 `attempt_status` / `rescore_accepted_count` / `actionable_review_count` 口徑必須與 review queue 對齊:統計「沒有新鮮有效 identity」的商品而不是只統計「完全沒有 identity」的商品已過期但可重算採用的 stale identity 仍應出現在待審數字中,避免 API 與 Dashboard 漏報。
- `run_retryable_candidate_revalidation()` 的自動回刷主戰場仍限 `low_score` / `refresh_low_score` / `recoverable_low_score``true_low_confidence` 只有在已補 focused exact 規則的窄範圍品線、舊分數 >= 0.95、`comparison_mode='exact_identity'`、含 `strong_exact_spec_match` 且不含 commercial / variant / count / bundle / refill 等阻擋理由時,才可進入重評,不得全面打開人工審核池。`rescore_accepted_current` 只允許命中具名 focused exact 品線、舊分數 >= 0.76、且仍無 hard veto / 阻擋理由時進窄門回刷;最後仍由最新版 matcher 判定是否可寫正式價差,像不同指甲油型號 / 色號必須 hard veto。
- 高分 `true_low_confidence` 的自動救回只能用具名 focused exact 線逐批擴充;同品牌、同品線、同規格/同組合的花美水 Relax、St.Clare 私密呼呼、BIOPEUTIC 果酸、台塑生醫嬰兒沐浴洗髮、Elizabeth Arden 八小時護唇膏與理膚寶水全面修復潤唇膏可走 total-price色號、香味、款式、即期品與 catalog selection 仍維持 review / veto。
- `true_low_confidence` focused exact 線必須同步接入 `run_retryable_candidate_revalidation()` 的 SQL 窄門,讓舊候選可被批次回收;該窄門只允許具名品線豁免 `variant_selection_review`,其他 hard veto / 型別、款式、香味、件數、組合、refill、commercial condition 阻擋仍不得回刷。
- 任選 catalog focused exact 只允許雙方都明確是同品線任選賣場且規格一致的窄範圍案例,例如 FLORTTE 眼線液筆 0.5ml、露得清護手霜 56g 無香/有香、Kanebo ALLIE 持采亮化 UV 防曬水凝乳 60g若有 `commercial_condition_gap`即期品、短效、航空版等狀態差異focused bypass 不得移除 `variant_selection_review`,不得自動寫正式價差。
- O.P.I 指彩救回只允許同品牌、同 `類光繚` / `如膠似漆` 指甲油或指彩線,且共享 `ISL...` 精準型號 token 的案例自動走 total-price不同型號/色號仍維持人工或 veto。此規則可接入 `true_low_confidence` revalidation 窄門,但不得變成「同品線即通過」。
- 其他正式覆核池 focused exact 線只能針對「已在正式頁面反覆出現且有硬規格」的窄範圍族群,例如 The Ordinary 咖啡因 EGCG、Natures Care 綿羊油同入數、TOMOON 指甲剪同尺寸、HH 雙 200ml 組、SEBAMED 200ml x2、YES 9cm 剪刀;同尺寸、同入數、同組合或單側漏規格必須可由 matcher 明確判斷,不能只因同品牌同品線通過。
- `/api/ai/pchome-match/backfill/status` 必須把近門檻重評池與過期 identity 救援池以只讀 `revalidation_preview` / `stale_recovery_preview` 曝光給操作員;預覽只復用正式候選 SQL 並受 limit / 60 秒快取限制,不啟動 PChome 搜尋、不呼叫 LLM、不寫 `competitor_match_attempts` / `competitor_prices`。重評 preview 必須先從最新 `competitor_match_attempts` 縮小候選,再用 `JOIN LATERAL` 取單一最新 MOMO 價;救援 preview 必須從過期 `competitor_prices` 小集合出發並用 `JOIN LATERAL` 取最新 MOMO 價,兩者都不得掃全量 `price_records`Dashboard 只能顯示「可救援」觀測值,不得在未開啟 `PCHOME_STALE_RECOVERY_ENABLED` 時提供 recover-stale 執行按鈕;其中 `review_gated_count` 僅代表窄門 `true_low_confidence` exact 候選,不得被解讀為全量人工池可自動回刷。
- PChome re-score audit 預設必須先取每個 SKU 的最新 `competitor_match_attempts` 狀態,再套用 status / reason 篩選;舊低信心歷史候選只能透過 `--include-historical-candidates` 明確進入考古掃描,避免已入隊、已否決或已修正 SKU 被舊紀錄重新推回報表。
- production re-score `--apply-accepted` 僅可追加 `rescore_accepted_current` attempt 給人工覆核;執行後需清除 Dashboard / competitor intel cache且必須抽查 `competitor_prices` / `competitor_price_history` 未新增正式價差。
- production re-score 若曾把 `variant_selection_review` 追加成 `rescore_accepted_current`,必須用 `audit_competitor_match_attempt_rescore.py --retract-variant-accepted` 追加最新 `true_low_confidence` 退回列;此路徑只寫 `competitor_match_attempts`,不得刪歷史紀錄,也不得寫 `competitor_prices` / `competitor_price_history`
- PChome matcher replay 必須先守住假陽性:`EX8` 等型號不可被誤解析成 `x8` 入數;香氛固體凝膠 / 空氣芳香劑若一側為泛稱、一側含明確香味或 No. 款式,必須走 `aroma_scent_variant_conflict` veto不得因同品牌同重量直接寫正式價差。
- PChome matcher 對「同規格同數量」的多件組可以安全回收,但必須同時滿足:商品型別完全對齊、品牌同線、規格與數量對齊、沒有 variant / count / bundle / commercial / unit-price / price-ratio 阻擋理由,才可打 `safe_multi_component_exact_total_price` 並進 `exact / total_price / price_alert_exact`混合組、香味款、色號款、catalog 任選仍需留在 `identity_review` 或 veto。護唇品 focused total-price 僅允許已明確建規則的 DHC 純欖 1.5g、FRUDIA 蜂蜜藍莓 10g、SEBAMED 嬰兒護唇膏 4.8g x2、理膚寶水滋養修護潤唇膏 4.7ml,不得把所有 lip/cosmetic catalog 一次放行。
- PChome feeder 正式寫入必須再套一層價格資料閘門:只有 `match_type='exact'``price_basis='total_price'``alert_tier='price_alert_exact'` 且無 `variant_selection_review` 的結果可以自動寫入 `competitor_prices``manual_review` / `identity_review` 只能留在覆核隊列或人工採用流程,不得由 retryable replay 或 known identity refresh 自動升成正式價差。Rescore audit 若遇到 `variant_selection_review`,也不得產生 `accepted_current`
| 角色 | 模型 | 主機 | 成本 | 每日限額 |
|------|------|------|------|---------|
| Hermes 分析師 | hermes3:latest / embedding model | 192.168.0.111:11434 或 188 Ollama | 零 | 無限 |
| NemoTron 派發器 | meta/llama-3.1-8b-instruct | NVIDIA NIM | 免費 80/天 | 80 |
| OpenClaw 策略師 | Gemini | 雲端 | 需審批 | — |
| Hermes 分析師 | hermes3:latest / bge-m3 | GCP-A → GCP-B → 111 Ollama | 零 | 無限 |
| NemoTron 派發器 | qwen3:14b111 fallback 降級 llama3.2NIM fallback | GCP-A → GCP-B → 111NVIDIA NIM 備援 | Ollama 零NIM 配額內免費 | NIM 80 |
| OpenClaw 策略師 | qwen2.5-coder:7b / qwen3:14b111 fallback 降級 llama3.2 | Ollama-firstGemini emergency fallback only | Ollama 零Gemini 預設封鎖 | — |
| ElephantAlpha 編排者 | ElephantAlpha | 依部署環境 | 受控 | HITL / 任務制 |
---
@@ -77,11 +198,11 @@ SQL漏斗(~300筆)
- `/metrics` 匯出 `momo_ai_event_router_replay_total`
- `/metrics` 匯出 `momo_ai_autoheal_action_total``momo_ai_autoheal_duration_ms_count/sum/max`
- `/metrics` 在尚無事件時仍輸出 `momo_ai_*` zero-baseline series讓 Prometheus/Grafana 重啟後可立即看到 metric names。
- `/ai_automation_smoke` 提供登入後 smoke dashboard
- `/ai_automation_smoke` 提供登入後 AI 自動化健康檢查頁
- `/api/ai-automation/smoke` 提供 read-only JSON 狀態,不做外部網路呼叫。
- Smoke API 會將最近檢結果保存到 JSONLdashboard 顯示最近狀態趨勢。
- Smoke history 支援 JSONL 匯出、清理與每日 OK / Warning / Critical 摘要。
- Smoke 每日摘要支援手動 Telegram 推播,並由 `momo-scheduler` 每日 09:10 呼叫 `run_ai_smoke_daily_summary_task()`
- 健康檢查 API 會將最近檢結果保存到 JSONL頁面顯示最近狀態趨勢。
- 健康檢查歷史支援 JSONL 匯出、清理與每日「正常 / 注意 / 嚴重」摘要。
- 健康檢查每日摘要支援手動 Telegram 推播,並由 `momo-scheduler` 每日 09:10 呼叫 `run_ai_smoke_daily_summary_task()`
- Grafana provisioning 新增 `docker/grafana/provisioning/dashboards/json/ai-automation-overview.json`,觀測 EventRouter dispatch/latency、safe action、Telegram replay 與 AutoHeal action/duration。
- Active monitoring stack 使用 `monitoring/prometheus.yml``momo-app` job scrape `momo-pro-system:80/metrics`Prometheus container 需加入 `momo-network`
- Active Blackbox HTTP targets 必須探測 `/health`188 stack 目前 `https://mo.wooo.work/health``http://momo-pro-system:80/health`110 gateway stack 目前 `https://mo.wooo.work/health`),不可探測 Dashboard 首頁 `/`,避免監控流量觸發重型 DB 查詢。
@@ -90,7 +211,19 @@ SQL漏斗(~300筆)
- Gunicorn runtime 預設 `worker_class = gthread``GUNICORN_THREADS=4``preload_app = False`;此組合讓 HUP 熱重載可用,也避免 Dashboard 長查詢完全阻塞 `/health`
- CD rebuild 模式必須先 build image 成功,再短暫 stop/rm/recreate 三應用容器,避免 no-cache build 造成長時間 502。
- ElephantAlpha 使用 NVIDIA NIM hosted APIproduction 預設模型為 `nvidia/llama-3.3-nemotron-super-49b-v1.5``ELEPHANT_ALPHA_FALLBACK_MODELS` 需保留至少一個可呼叫備援403/404、408/409/425/429、5xx、timeout 與 connection error 必須嘗試下一個模型。
- OpenClaw/Hermes embedding 優先呼叫 Ollama `/api/embed`,只在舊節點不支援時 fallback `/api/embeddings`timeout 由 `EMBEDDING_TIMEOUT` / `OLLAMA_EMBED_TIMEOUT` 控制
- ElephantAlpha L3 HITL 只允許發送有實證、可審核、可行動的升級告警;價格類 trigger 無 Hermes 具體威脅時,只記錄 suppressed escalation telemetry 與 cooldown不寫 pending `human_review`,不發 Telegram 空告警
- ElephantAlpha 價格類 trigger 的 HITL / 決策 prefetch 必須先使用觸發 SQL 與 `competitor_prices` / `price_records` 的 DB 實證生成 SKU、MOMO / PChome 價差與建議 action lines完整 Hermes LLM prefetch 預設關閉(`ELEPHANT_ALPHA_HERMES_LLM_PREFETCH_ENABLED=false`),避免 5s timeout 後落入無實證摘要或雲端備援。若無 DB 實證,只記錄 suppressed telemetry / cooldown不發 Telegram 空告警。
- ElephantAlpha `price_drop_alert` / `market_opportunity` trigger 不得對整張 `price_records` 做全表最新價聚合;必須先篩最近有效 `identity_v2` PChome 候選,再用 per-SKU `JOIN LATERAL` 讀最新 MOMO 價格,並把 `match_score``tags``match_diagnostic_json` 帶入 evidence。
- ElephantAlpha 協調器收到非純 JSON、fenced JSON 或混文字 JSON 時,必須先做容錯抽取;仍無法解析時,只能使用 DB/Hermes 實證生成保守 HITL fallback。fallback 不得放入 OpenClaw `generate_*` 類舊策略步驟,也不得暗示已自動調價。
- V10.624 起 ElephantAlpha 價格類 trigger 即使信心度達自主門檻,也只能發送 HITL 價格覆核通知;必須跳過 orchestrator `execution_plan` 內的 Hermes/NemoTron/OpenClaw 長任務 step。這是價格決策護欄避免 60 秒 execution timeout 卡住 scheduler也避免把價格策略誤描述為已自動執行。
- ElephantAlpha 執行器若遇到舊版 OpenClaw strategy 類步驟(含 `generate_market_strategy` / `generate_dynamic_pricing_strategy` / `generate_resource_optimization_strategy`),只能記錄為 advisory skipped不得觸發 circuit breaker也不得轉成實際排程、外部呼叫或價格行動。
- `resource_optimization` 不再交給 LLM 生成「預期效益 / 已執行」敘事,顯示名稱統一為「資源壓力治理」。此 trigger 必須先由程式量測 `action_plans` backlog、P1/P2 數、pending_review、逾時項目與 CPU load只有 CPU 達門檻、P1/P2 積壓或逾時積壓才發 Telegram「資源壓力告警」。單純 queue 大但 CPU 正常只記錄 telemetry不派發 Hermes/NemoTron、不宣稱 48 小時效益Telegram 段落使用「系統處置紀錄」而非泛稱「已執行」,避免暗示 AI 已完成未經驗證的外部動作。
- `resource_optimization` 的 Telegram 必須包含 `decision_envelope` 區塊,標明 `source_agent=elephant_alpha`、資料品質、量測證據、`can_auto_execute=false` 與 deterministic trace此路徑不呼叫 Gemini、不呼叫 Hermes/NemoTron也不得把 queue backlog 翻譯成主機資源耗盡。
- `resource_optimization` 會先執行 `ActionPlanHygieneService` 清理過期噪音:只關閉超過 72 小時的 `code_review_fix` / `openclaw_recommendation` 類 advisory action_plans以及 NemoTron `direct_response/reply_simple` 舊聊天回覆計畫;將狀態改為 `auto_disabled``rejected` 並寫入 `metadata_json.hygiene_history`。不刪資料,也不碰 NemoTron human_review / pricing / tool action 類業務行動。
- `momo-scheduler` 每 6 小時固定執行 `run_action_plan_hygiene_task()`,讓過期 advisory action_plans 的關閉不再依賴 `resource_optimization` 告警觸發;排程失敗會經 EventRouter 發送 `action_plan_hygiene_failure`
- `action_plans` 產生端必須防重Code Review 同一檔案已有 active `code_review_fix` 時不重建OpenClaw recommendation 會寫入文字 fingerprint 並跳過同一建議AIOrchestrator 不再把 NemoTron `direct_response/reply_simple` 聊天回覆存成 action plan真正需工具、審核或執行的 NemoTron action 才能進 queue。
- OpenClaw/Hermes embedding 優先呼叫 Ollama `/api/embed`,只在舊節點不支援時 fallback `/api/embeddings`timeout 由 `EMBEDDING_TIMEOUT` / `OLLAMA_EMBED_TIMEOUT` 控制,並受 `OLLAMA_EMBED_MAX_TIMEOUT` 封頂。背景 worker / RAG 查詢不得落 111除非 caller 顯式允許 `allow_111_fallback=True`
- PPT 自動產線由 `momo-scheduler` 依節奏執行 `run_ppt_auto_generation_task(schedule_kind)`:每日 20:30 產日報、週一 20:40 產週報/市場情報、每月 1 日 20:50 產月報與管理型簡報、季初 21:00 產季報、半年初 21:10 產半年報、年初 21:20 產年報,再交給 22:00 `ppt_vision_audit` 做視覺審核;每次嘗試會寫入 `ppt_generation_runs``/observability/ppt_audit_history` 以精準參數檢查目標版本是否已產生,並可用 `/observability/ppt_audit/generate_missing` 手動補齊缺漏,總開關為 `PPT_AUTO_GENERATION_ENABLED`。PPT vision 需 `PPT_VISION_ENABLED=true` 與容器內 LibreOffice`/observability/ppt_audit_file/<filename>` 會把 PPTX 轉成 PDF 快取供站內線上預覽,原始 PPTX 仍保留下載。QA 失敗項目的「重跑」必須從檔名推回原 report_type並只失效相同 `report_type + parameters` 的 active `ppt_reports` cache避免拿到舊 PPT 或誤重跑 daily。
---
@@ -125,19 +258,20 @@ SQL漏斗(~300筆)
> ⚠️ **架構限制**: `price_records` **只存 MOMO 自家售價**,無 `source` 欄位無競品PChome價格。
> PChome 比價資料必須由外部爬蟲即時抓取,以 `pchome_prices: dict` 形式注入 `HermesAnalystService.run()`。
### 2.3 `daily_sales_snapshot` 表(動態表,從 Excel 匯入
### 2.3 `daily_sales_snapshot` 表(PChome 後台業績匯出,動態表)
> **重要**: 此表由 `import_service.py` 使用 `df.to_sql()` 動態建立。
> 欄位名稱**完全繼承自匯入的 MOMO Excel 報表原始欄位**,加上程式碼追加的 `snapshot_date`。
> 欄位名稱**完全繼承自 PChome 後台匯出的業績 Excel 原始欄位**,加上程式碼追加的 `snapshot_date`。
> V10.605 起,匯入器會掃描所有 worksheet 與前 15 列表頭,優先選擇含「日期 / 商品名稱 / 總業績或銷售金額」的明細工作表;格式或日期真的不合格的檔案會移到 Google Drive `匯入失敗`,避免每 30 分鐘重複告警。
#### 已確認的關鍵欄位(實際 MOMO 報表欄位名稱)
#### 已確認的關鍵欄位(PChome 後台報表欄位名稱)
| 欄位 | 型別 | 說明 | 備注 |
|------|------|------|------|
| `snapshot_date` | Date | 資料所屬日期(程式追加) | 由 `import_service.py` 從「日期」欄位解析 |
| `商品ID` | VARCHAR | **商品識別碼**= `products.i_code` | ⚠️ 非 `商品編號`|
| `商品ID` | VARCHAR | PChome 後台 / 訂單目錄商品識別碼 | ⚠️ 不可假設等於 `products.i_code` |
| `商品名稱` | TEXT | 商品名稱 | |
| `銷售金額` | NUMERIC | 銷售業績金額 | 系統以 find_col 模糊比對,優先 `銷售金額` |
| `總業績` / `銷售金額` | NUMERIC | 銷售業績金額 | 匯入器以欄位群組模糊比對,兩者皆可 |
| `數量` | NUMERIC | 銷售數量 | |
| `總成本` | NUMERIC | 成本 | |
| `廠商名稱` | VARCHAR | 廠商名稱 | |
@@ -171,10 +305,10 @@ SKU/商品ID = find_col(['商品ID', 'Product ID', 'ID', 'i_code', 'Item Code'
| `discount_pct` | INTEGER | 折扣 %NULL=未折扣) |
| `competitor_product_id` | VARCHAR(100) | PChome 商品 ID |
| `competitor_product_name` | TEXT | PChome 商品名稱(核對用) |
| `match_score` | NUMERIC(4,3) | 模糊比對分數0~1< 0.45 不寫入 |
| `match_score` | NUMERIC(4,3) | 商品身份比對分數0~1< 0.76 不寫入正式快取 |
| `tags` | JSONB | 語意標籤,如 `["on_sale","discount_20pct"]` |
| `crawled_at` | TIMESTAMP | 爬取時間 |
| `expires_at` | TIMESTAMP | TTL = crawled_at + 6h過期後 Hermes 忽略 |
| `expires_at` | TIMESTAMP | TTL = crawled_at + 48h可由 `PCHOME_FEEDER_TTL_HOURS` 調整),過期後 Hermes 忽略UI 身份覆蓋率不因價格 TTL 過期歸零 |
**UNIQUE**: `(sku, source)` — 同一 SKU+來源只有一筆ON CONFLICT UPDATE
@@ -209,9 +343,11 @@ CREATE TABLE IF NOT EXISTS ai_price_recommendations (
---
## 三、SQL 漏斗設計(已修正欄位名稱
## 三、SQL 漏斗設計(PChome 業績 ID 邊界
`hermes_analyst_service.py` `fetch_candidates()` 的核心 SQL
`daily_sales_snapshot` 來自 PChome 後台業績匯出,`商品ID` `products.i_code` 不保證同一套 ID。任何跨表分析必須先經過可驗證的 mapping / identity contract不能只用字串相等把 PChome 後台銷售資料與 MOMO 商品主檔硬接。
歷史上曾以如下漏斗概念描述近 7 天銷售額下滑,但此 SQL 只能在 ID 已確認同源時使用:
```sql
WITH latest_momo_price AS (
@@ -249,10 +385,10 @@ ORDER BY (rs.sales_7d_curr - rs.sales_7d_prev) / rs.sales_7d_prev ASC
LIMIT 300
```
**漏斗效果**: 226萬筆 price_records → ~300 筆近7天銷量跌幅 > 10% 的活躍商品)
**JOIN 邏輯**:
- `products.i_code``daily_sales_snapshot."商品ID"` — 均為 MOMO 商品代碼,格式相同
**ID 邊界**:
- `products.i_code` 是 MOMO 商品主檔 / 價格爬蟲 SKU。
- `daily_sales_snapshot."商品ID"` 是 PChome 後台業績匯出中的商品識別碼。
- 兩者不可被文件、Agent 或報表預設視為相同。需要合併分析時,必須先建立可審核 mapping 或沿用已驗證的 PChome identity / 商品名稱證據。
---
@@ -263,13 +399,13 @@ LIMIT 300
```
[competitor_price_feeder.py Worker] ←← 每 4 小時獨立運行
↓ 搜尋 PChomesearch_products
模糊比對price_comparison.py
商品身份比對marketplace_product_matcher.py
↓ 提取語意標籤
↓ UPSERT competitor_pricesTTL 6h
↓ UPSERT competitor_prices預設 TTL 48h
[HermesAnalystService.fetch_candidates()] ←← AI Pipeline 消費端
↓ LEFT JOIN competitor_prices零網路等待
↓ 有效期內expires_at > NOW()+ match_score ≥ 0.45 才 JOIN
↓ 有效期內expires_at > NOW()+ match_score ≥ 0.76 + tags 含 identity_v2 才 JOIN
↓ pchome_price + competitor_tags 一起傳給 Hermes
```
@@ -279,19 +415,24 @@ LIMIT 300
|------|------|------|
| 解耦方式 | DB 表快取(非 Redis | PostgreSQL 已是核心,無需額外依賴;支援 JOIN |
| TTL | 6 小時 | 與 AI Pipeline 排程週期對齊 |
| 比對算法 | 品牌(0.4) + 規格(0.3) + 關鍵字(0.3) | 依賴現有 `price_comparison.py` |
| 最低比對門檻 | 0.45 | 低於此分數不寫入,避免張冠李戴影響 AI 決策 |
| 比對算法 | 品牌 + 核心 token + 容量/重量/包數 + 品類 + 價格 sanity check | 由 `marketplace_product_matcher.py` 統一供 feeder、legacy crawler、AI/PPT 鏈路使用 |
| 最低比對門檻 | 0.76 | 核心比價寧可待審,不允許低信心錯配影響 AI 決策 |
| 已有不同 PChome 商品覆蓋門檻 | 0.84 | 新候選與既有正式配對不同時,除非超高信心,否則寫入 `needs_review` attempt 不覆蓋 |
| 單位價可比模式 | `unit_comparable` | 同核心商品但買送/套組/件數不同時,不寫正式總價差;只寫入 attempt並以單位價證據供 Dashboard / PPT / AI 報表與人工覆核 |
| Browse.sh 診斷 | optional wrapper | 只用於 selector / XHR / network trace 探勘;不得取代正式 crawler也不得直接把輸出寫成正式競品價格 |
| 語意標籤 | JSONB 陣列 | 傳給 Hermes 提升情境感知品質 |
### 競品比對邏輯(`competitor_price_feeder.py`
```
MOMO 商品名稱[:20字]
PChomeCrawler.search_products(keyword, limit=10)
_find_best_match(momo_name, results)
ProductNameParser品牌 + 規格 + 關鍵字)
_structural_similarity() → score
→ score ≥ 0.45 → _upsert_competitor_price()
MOMO 商品名稱
marketplace_product_matcher.build_search_terms()
PChomeCrawler.search_products(keyword, limit=12)
marketplace_product_matcher.score_marketplace_match()
品牌衝突 / 容量衝突 / 包數衝突 hard veto
→ 同核心但買送/套組/件數不同標記 unit_comparable不進正式總價差
→ 同款高信心 score ≥ 0.76 才進 competitor_prices
→ 低信心、規格衝突、既有配對衝突寫入 competitor_match_attempts
```
### `fetch_candidates()` v2 漏斗(已更新)
@@ -301,16 +442,43 @@ LEFT JOIN competitor_prices cp
ON cp.sku = lmp.sku
AND cp.source = 'pchome'
AND cp.expires_at > NOW()
AND cp.match_score >= 0.45
AND cp.match_score >= 0.76
AND COALESCE(cp.tags, '[]'::jsonb) ? 'identity_v2'
```
→ 無競品資料的商品仍回傳,`pchome_price=NULL``_batch_analyze` 自動跳過
### 下游消費規範2026-05-19 更新)
- Dashboard、AI pick、Hermes、Excel export、daily/growth 圖表與 competitor PPT 必須以 `competitor_prices + competitor_price_history + competitor_match_attempts` 為短期唯一生產真相源,且只消費 `identity_v2` matcher 驗證過的配對;舊版僅靠 `match_score` 的快取不可直接進入決策或簡報。
- `pchome_matches` 與 live `pchome_batch()` 僅保留 legacy compatibility不得作為新簡報或 AI 決策主來源。
- `services/competitor_intel_repository.py` 是下游頁面、圖表、簡報的共用查詢出口;新增消費端不得各自硬寫不同 match threshold。所有競品報表的價差方向統一為 `MOMO - PChome`:正值代表 MOMO 較貴 / PChome 低價壓力,負值代表 MOMO 價格優勢daily、growth、OpenClaw、PPT 不得使用反向定義。
- competitor PPT 不可只輸出 matched rows 造成覆蓋率假象;`fetch_competitor_comparison_results()` 必須用 `LEFT JOIN valid_competitor` 保留高營收/高價但尚未有效配對的 MOMO 商品,並帶出 `match_status``candidate_count``best_match_score``match_diagnostic`,讓簡報與 AI 文案明確區分「高信心比對」與「待補身份/價格」。
- `services/competitor_identity_revalidator.py` 可對既有 `competitor_prices` legacy row 離線重跑 `identity_v2`:只有新版 matcher 分數 `>= 0.76` 且無 hard veto 才補 `identity_v2` / `legacy_revalidated` tags預設不刷新 `expires_at`,避免過期價格進入決策。
- `CompetitorPriceFeeder.run_expired_identity_refresh()` 會優先刷新已通過 `identity_v2` 但 TTL 過期的 PChome row直接用既有 `competitor_product_id` 批次呼叫 PChome 商品 API再用新版 matcher 重新驗證名稱/規格/價格 sanity通過後寫回 `competitor_prices``competitor_price_history`。這條路徑提升新鮮價格覆蓋率,但不降低 match threshold也不讓過期價格直接進入決策佇列排序必須先處理既有 `price_basis_total_price` / `alert_tier_price_alert_exact` 或 diagnostic 等價欄位的安全價差 row再處理需要 review 的舊 row。若既有 `competitor_product_id` 已查不到或回傳候選低於門檻expired refresh 只寫 `refresh_no_result` / 低信心 attempt 並標記 `fresh_search_recovery_deferred`,不得在同一條價格刷新路徑 fresh search 替換正式 identity。fresh search recovery 只保留給 retryable candidate revalidation / unmatched priority 等補抓路徑。
- 過期 identity refresh 排序必須優先 `price_basis_total_price` / `alert_tier_price_alert_exact``match_diagnostic_json.price_basis='total_price'` / `alert_tier='price_alert_exact'` 的正式價差配對,再依 `expires_at` 與 MOMO 價格排序,避免高風險可決策價差長期排在低價或非告警型 stale row 後面。
- `marketplace_product_matcher.py` 的擴充只能走「正向證據 + 反向 veto」品牌一致、商品線/型號訊號強、價格合理且無 hard veto 時才允許 `strong_product_line_match` 加分;補充瓶/補充包/refill 與一般正裝不互相配對,分享組/加量組/明星組等組合包不得誤配單品。
- 近門檻規則必須成對補「召回 + 防錯配」測試:可召回者需有品牌、商品線、規格或具名 identity anchor例如 MUJI 精油芬香護手霜、Mustela 慕之幼爽身潤膚乳、Herbacin 小甘菊護手霜;防錯配者需成為 hard veto例如 M·A·C Macximal 柔霧/緞光唇膏質地、ERBE 指甲清垢棒/指甲緣刨刀功能、Schick 舒芙/舒綺女用除毛刀品線。不得用單一同規格或同品牌放寬全域門檻。
- 套組/買送/件數不同但品牌、核心商品線與單一基礎規格一致時matcher 必須回傳 `comparison_mode='unit_comparable'``unit_comparable` reasonFeeder 只能寫入 `competitor_match_attempts.attempt_status='unit_comparable'``refresh_unit_comparable`,不得寫入 `competitor_prices`。Dashboard 與 `competitor_intel_repository` 必須用 `build_unit_price_comparison()` 產生每 ml / 每 g / 每入單位價證據,讓 PPT / AI 報表可說明「需單位價比較」而不是把總價當同款價差。商品看板在正式配對尚未成立時,仍必須顯示最佳候選 PChome 商品名稱、候選價與「候選價需單位換算」說明讓人工覆核可直接看見下一步daily/growth、PPT 與 OpenClaw 摘要不得自建查詢,需消費 `fetch_competitor_review_queue()` 與 coverage 的 `unit_comparable_count`。若任一側含多個不同容量/重量規格,視為多品項套組,不可進 `unit_comparable`
- PChome feeder 的外部 request timeout 由 `PCHOME_FEEDER_TIMEOUT` 控制,預設 12 秒;排程不得因單一 PChome 搜尋 API timeout 被拖到數分鐘。
- 品牌 alias 屬於正向身份證據,不是門檻放寬;`DR.WU / DR WU / DRWU / 達爾膚` 這類同品牌中英混寫必須正規化後再進 matcher避免同規格真同款被誤降成 brandless identity review。
- 近門檻 rescore pilot 必須支援明確 SKU 篩選;`audit_competitor_match_attempt_rescore.py --sku <sku>` 可只重算指定 SKU避免為了小批次驗證而掃整批 `true_low_confidence`
- 商品看板的 PChome 狀態必須把 matcher 診斷原因翻成可行動語意:品牌不符已排除、規格不符已排除、補充包不相容、組合規格不相容、系列不符已排除、需單位價比較、低信心待補強等,不可只顯示籠統「待比對」或「身份否決」。
- PChome 補抓產線與 priority list 若尚未進入搜尋/補抓必須顯示「PChome 補抓產線」、「尚未搜尋」與「尚未進入 PChome 補抓」,不得使用「待比對」這類會被誤解成已有候選待人工審核的字眼。
- 商品看板、PChome review queue 與 `/api/export/excel/pchome-review` 必須優先讀取 `match_diagnostic_json.reasons` 並轉成操作員可讀標籤;文字版 `error_message` 只作 legacy fallback。商品列的 PChome 狀態摘要也必須使用同一套專業標籤,避免 overview 顯示「妝效質地不同」但列表仍顯示籠統身份不符。新增 matcher reason 時需同步更新 `MATCH_DIAGNOSTIC_REASON_LABELS` 與 dashboard 狀態翻譯,避免 UI 顯示 `makeup_finish_conflict` 這類 machine code。PChome 標題缺品牌但有窄範圍 exact identity anchor 的商品,只能透過具名 brandless recovery 進 manual-review identity多色任選 / 單一色號 gap 必須標記 `variant_selection_review`,並從 `recoverable_low_score` 降回 `true_low_confidence`,不得自動批次寫正式價差。
- Dashboard 必須把「待比對」拆成可診斷狀態:`價格過期待刷新``舊版配對待重驗``低分配對待補強``已排除``需單位價比較``找不到同款``抓取異常``尚未搜尋`。硬性不相容候選應顯示為已排除/不相容,不得讓使用者誤以為每筆都需要人工待審。
### 執行方式
```bash
# 手動觸發一輪抓取
python3 services/competitor_price_feeder.py
# 預覽 legacy PChome 快取 identity_v2 重驗證(不寫入)
python3 -m services.competitor_identity_revalidator --limit 500
# 寫入安全通過的 identity_v2 tag不刷新過期價格
python3 -m services.competitor_identity_revalidator --limit 500 --apply
# 未來整合為 K3s CronJob每 4 小時)
# k8s/jobs/competitor-price-feeder-cronjob.yaml
```
@@ -325,6 +493,9 @@ python3 services/competitor_price_feeder.py
2. **倒金字塔結構** — 結論先行 → 核心數據 → AI 洞察 → 建議行動 → 運算足跡
3. **收斂行動呼籲 (Call to Action)** — 每則訊息只有一個明確的 👉 建議行動
4. **底部運算足跡** — FinOps + Observability用分隔線隔開主訊息
5. **EA HITL 專業 brief**`ea_escalation` 必須分成決策狀態、背景摘要、風險摘要、TOP 待審 SKU 與建議處置;價格類行動不得用長 bullet 串接,必須拆出 MOMO/PChome 價格、價差、人工處置與 PChome ID。
6. **價格類決策信封專業 brief**`price_alert``pchome_match_review``competitor_price_review` 等含 PChome / 價格證據的 `decision_envelope`EventRouter 必須直送 evidence template不得進 L1/L2 重摘要Telegram 內容必須拆成「標的、價格證據、比對證據、人工下一步」,並從信封讀取 `momo_price``competitor_price``candidate_gap_pct``match_score``unit_price_insight``existing_match_conflict`
7. **Shared UI 信封摘要共用** — Webcrumbs host data 與其他共用 UI runtime 必須讀 `reviewDecisionBrief` / `decision_envelope` 的結構化證據,不在瀏覽器端重組比價判斷;這些 payload 只能讀 DB 既有覆核資料,不呼叫 LLM、不抓外站、不寫資料。
### 5.2 語意化 Emoji 字典
@@ -363,7 +534,7 @@ python3 services/competitor_price_feeder.py
─────────────────────
⚙️ 運算足跡:
• 🔍 分析: Hermes 3 8B (本地 111) | 耗時: 34.2s | Tokens: 512 | $0 成本
• 🔍 分析: Hermes 3 8B (GCP-A/GCP-B/111 Ollama) | 耗時: 34.2s | Tokens: 512 | $0 成本
• ⚡ 決策: NemoTron NIM | 185 Tokens | $0 (配額內 2/80)
```
@@ -386,7 +557,7 @@ python3 services/competitor_price_feeder.py
─────────────────────
⚙️ 運算足跡:
• 🔍 分析: Hermes 3 8B (本地 111) | 耗時: 34.2s | Tokens: 512 | $0 成本
• 🔍 分析: Hermes 3 8B (GCP-A/GCP-B/111 Ollama) | 耗時: 34.2s | Tokens: 512 | $0 成本
• ⚡ 決策: NemoTron NIM | 185 Tokens | $0 (配額內 2/80)
```
@@ -407,18 +578,18 @@ python3 services/competitor_price_feeder.py
─────────────────────
⚙️ 運算足跡:
• 🔍 分析: Hermes 3 8B (本地 111) | 耗時: 34.2s | Tokens: 512 | $0 成本
• 🔍 分析: Hermes 3 8B (GCP-A/GCP-B/111 Ollama) | 耗時: 34.2s | Tokens: 512 | $0 成本
• ⚡ 決策: NemoTron NIM | 185 Tokens | $0 (配額內 2/80)
```
#### 類別四(未來)Gemini 雲端推理週報
#### 類別四Gemini 備援 / 鎖定場景推理週報
```
... (前文省略) ...
─────────────────────
⚙️ 運算足跡:
• 🔍 彙整: Hermes 3 8B (本地 111) | 耗時: 12s | $0 成本
• 🧠 推理: Gemini 1.5 Flash | 8,420 Tokens | 費用: 約 $0.003 USD
• 🔍 彙整: Hermes 3 8B (GCP-A/GCP-B/111 Ollama) | 耗時: 12s | $0 成本
• 🧠 備援/鎖定場景: Gemini 2.5 Flash | 8,420 Tokens | 費用: 約 $0.003 USD
```
### 5.4 運算足跡資料來源
@@ -452,14 +623,14 @@ python3 services/competitor_price_feeder.py
### 告警群組
- 群組: **小龍蝦** (業務情報專用,非 SRE 維運)
- Chat ID: `-1003940688311`
- Bot: `8610496165:AAFOlcWV4oRUSC2TI-fYux7JV97fjNzsYR8`
- Bot: `<TELEGRAM_BOT_TOKEN>`
### 單 Bot 多身份策略One Bot, Multiple Headers
| 模組 | Telegram 標頭 |
|------|--------------|
| Hermes 分析師 | `[Hermes 分析師]` |
| NemoTron 派發器 | `[NemoTron 派發器]` |
| Gemini 策略師 | `[Gemini 策略師]` (未來) |
| Gemini 備援 | `[Gemini 備援]`(僅 Ollama 失敗或 ADR-028 鎖定場景) |
### 三種告警類型
| Tool | 觸發條件 | Telegram 格式 |
@@ -476,7 +647,7 @@ python3 services/competitor_price_feeder.py
| 參數 | 值 |
|------|---|
| 模型 | `hermes3:latest` |
| Ollama URL | `http://192.168.0.111:11434` |
| Ollama URL | GCP-A `http://34.87.90.216:11434` → GCP-B `http://34.21.145.224:11434` → 111 `http://192.168.0.111:11434` |
| Timeout | 120s |
| Temperature | 0.1 |
| 實測推理時間 | **19.3s3筆實彈 2026-04-17** |
@@ -504,9 +675,10 @@ python3 services/competitor_price_feeder.py
| ✅ | momo-app 雙網路連線 | 同時連 `momo-network` + `momo-pro_default`(後者含 `momo-db` alias `momo-postgres`|
| P1 | PChome Feeder CronJob | `competitor_price_feeder.py` 每 4 小時排程 (Scheduler 整合) |
| P1 | 告警去重 TTL | 同一 SKU 短期內重複告警未防範 |
| P1 | `daily_sales_snapshot` 欄位防禦 | 若 Excel 欄位名變更JOIN 條件會靜默失效 |
| | `daily_sales_snapshot` 欄位防禦 | V10.605 已支援多 worksheet / 表頭列掃描 / 格式失敗隔離 |
| P1 | PChome 後台業績匯出前半段自動化 | 現有 importer 已自動吃 Google Drive仍需接 PChome 後台排程匯出、Email 附件或受控 browser 下載 |
| P2 | Scheduler 整合 | 每6小時自動觸發 Hermes→NIM→Telegram 管線 |
| P2 | Gemini 策略師 | 週報生成(需費用審批後實作) |
| P2 | Gemini 備援治理 | 僅保留 ADR-028 鎖定場景與 Ollama 失敗備援,新增 caller 必須走 ADR |
---
@@ -519,15 +691,17 @@ python3 services/competitor_price_feeder.py
| PostgreSQL | 192.168.0.188 | `momo-db` | pgvector/pgvector:pg14含所有 AI 相關表 |
| momo-app | 192.168.0.188 | `momo-pro-system` | **Up healthyport 5002:80**5001 被 docker-registry 佔用,已改 5002 |
| momo-scheduler | 192.168.0.188 | `momo-scheduler` | 常駐排程容器 |
| Hermes 3 8B | 192.168.0.111 | Ollama 原生 | `hermes3:latest`E2E 可達 |
| Ollama Primary | 34.87.90.216 | Ollama 原生 | GCP-AAI/LLM/embedding 主路徑 |
| Ollama Secondary | 34.21.145.224 | Ollama 原生 | GCP-B同等備援 |
| Ollama Fallback | 192.168.0.111 | Ollama 原生 | 最後一道本地防線 |
| E2E 驗證容器 | 192.168.0.188 | `momo-e2e-test` | 臨時容器,含新服務模組 |
### 188 `/home/ollama/momo-pro/.env` 正確設定
```bash
TELEGRAM_BOT_TOKEN=8610496165:AAFOlcWV4oRUSC2TI-fYux7JV97fjNzsYR8 # ← 唯一正確 token
TELEGRAM_BOT_TOKEN=<TELEGRAM_BOT_TOKEN> # ← 唯一正確 token
TELEGRAM_CHAT_IDS=["-1003940688311"] # 小龍蝦群組
NVIDIA_API_KEY=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
NVIDIA_API_KEY=<NVIDIA_API_KEY>
USE_POSTGRESQL=true
POSTGRES_HOST=momo-db
# POSTGRES_DB / USER / PASSWORD 使用 docker-compose.yml 預設值
@@ -542,7 +716,7 @@ POSTGRES_HOST=momo-db
| 日期 | 問題 | 修正 |
|------|------|------|
| 2026-04-17 | `fetch_candidates()` SQL 使用 `"商品編號"` | 修正為 `"商品ID"`(與 MOMO Excel 實際欄位名一致) |
| 2026-04-17 | `fetch_candidates()` SQL 使用 `"商品編號"` | 修正為 `"商品ID"`2026-06-15 追認此欄位來自 PChome 後台業績匯出,不可預設等於 MOMO `products.i_code` |
| 2026-04-17 | Hermes gap_pct 由 LLM 計算 → 誤差大 | 改為 Python 預算 `(momo-pchome)/pchome*100` |
| 2026-04-17 | 推理時間 52s | 預算 gap_pct 後降至 19.3s (3筆) |
| 2026-04-17 | `model_footprint` DB 欄位寫入 `{}` | 分離 `footprint_text`Telegram 顯示)與 `footprint_data`DB JSON|
@@ -551,3 +725,11 @@ POSTGRES_HOST=momo-db
| 2026-04-17 | 188 容器無 volume mount`docker cp` 臨時解 | 重建 image`COPY . .` bake 進新代碼port 5001 衝突記錄為技術債 |
| 2026-04-17 | 188 .env Telegram token 不正確split-brain| 修正為 `8610496165`188→Telegram message_id=282 確認 |
| 2026-04-17 | NIM Tool Calling E2E | 真實 NVIDIA_API_KEY 驗證dispatched=3, errors=[] |
| 2026-05-20 | PChome 商品身份比對仍可能因單一規格重疊誤放行 | V10.312 起 matcher 解析 mg/mcg 劑量、件組套組、多規格集合與同數字不同單位;劑量/容量/重量/件數/品類衝突會硬否決或導向單位價覆核,避免錯配污染 Dashboard、daily/growth、PPT 與 AI 競價分析 |
| 2026-05-20 | 正確 PChome 候選常因只掃第一頁或搜尋詞丟失品牌/規格而未進入 matcher | V10.314 起搜尋 API 依 limit 掃多頁、對暫時性錯誤有限重試feeder 預設 5 組搜尋詞、20 候選、2 頁,並保留括號/方括號內品牌與規格,提升覆核隊列與正式比價的候選品質 |
| 2026-05-20 | 指定日期競品簡報可能混用目前 `competitor_prices` 快取價 | V10.315 起 `fetch_competitor_comparison_results()` 有 start/end date 時改用 `competitor_price_history` 期間快照MOMO 價格取報表結束日前最新價;即時報表才使用目前有效 `competitor_prices` |
| 2026-05-20 | PChome 覆蓋率分子可能被非活躍或無 MOMO 現價 SKU 膨脹 | V10.317 起 `fetch_competitor_coverage()``valid_matches` 改為 active MOMO latest price 與有效 PChome `identity_v2` 價格交集,確保 daily/growth/PPT/AI 看到的比價資料品質不被舊快取列高估 |
| 2026-05-20 | EA HITL 告警可能把非 SKU 診斷誤排成待審 SKU或在缺少 DB/Hermes 實證時打擾人工 | V10.318 起 `ea_escalation` 僅對含 SKU/價格比較的 actions 使用競價卡片;非 SKU 診斷改為「待確認事項」。價格類低信心事件若無 DB/Hermes 實證,測試鎖定只 suppress、不寫 human_review、不發 Telegram |
| 2026-05-21 | ElephantAlpha NIM/LLM 回應偶爾不是純 JSON會觸發 `json.loads()` 失敗並落入舊式空泛策略 fallback | V10.383 起協調器容忍 fenced/混文字 JSON無法解析時改用 DB/Hermes 實證 fallback且 fallback 不再包含 OpenClaw `generate_*` 舊步驟或自動調價暗示 |
| 2026-05-20 | Telegram HTML parse mode 不支援 `<br>`,可能導致告警或報告送出 400 | V10.321 起 Telegram template 發送前會把 `<br>` / `<br/>` / `<BR />` 轉為換行;保留其他 HTML 標籤,非 HTML parse mode 不改寫 |
| 2026-05-20 | 部分舊 Telegram 入口繞過中央 sanitizer且 RAG awaiting review 使用錯誤 `chat_id=` 參數會讓人工審核推播失敗 | V10.322 起 Bot API price decision 走 `send_telegram_with_result()``price_decision()``report_url` 相容並 escape 動態欄位RAG awaiting review 改用 `chat_ids=[...]` 呼叫 `_send_telegram_raw()` |

View File

@@ -3,7 +3,7 @@
## ✅ 已完成的設定
### 1. Telegram Bot 配置
- **Bot Token**: 8075645931:AAH-EGKMo8ZC4QJs-Nc1_0s92xHrGdQvdpg
- **Bot Token**: <TELEGRAM_BOT_TOKEN>
- **接收者 Chat ID**:
- 5619078117
- 961168381

View File

@@ -686,7 +686,7 @@ OLLAMA_CONFIG = {
'base_url': 'http://192.168.0.188:11434', # 內部 Ollama 伺服器
'model': 'gemma3:4b',
'timeout': 120,
'api_key': '0df8b4f247a4497998248f013ce92a17.vqSWDEK0RppTZIwcdT-ei-Sz'
'api_key': '<OLLAMA_API_KEY>'
}
```
@@ -1409,7 +1409,7 @@ document.addEventListener('DOMContentLoaded', function() {
- **IP**: 192.168.0.188
- **Port**: 11434
- **Model**: gemma3:4b
- **API Key**: `0df8b4f247a4497998248f013ce92a17.vqSWDEK0RppTZIwcdT-ei-Sz`
- **API Key**: `<OLLAMA_API_KEY>`
### 網路設定確認
```bash
@@ -1426,7 +1426,7 @@ curl http://192.168.0.188:11434/api/generate \
# Ollama 伺服器設定
OLLAMA_BASE_URL = os.getenv('OLLAMA_BASE_URL', 'http://192.168.0.188:11434')
OLLAMA_MODEL = os.getenv('OLLAMA_MODEL', 'gemma3:4b')
OLLAMA_API_KEY = os.getenv('OLLAMA_API_KEY', '0df8b4f247a4497998248f013ce92a17.vqSWDEK0RppTZIwcdT-ei-Sz')
OLLAMA_API_KEY = os.getenv('OLLAMA_API_KEY', '<OLLAMA_API_KEY>')
OLLAMA_TIMEOUT = int(os.getenv('OLLAMA_TIMEOUT', '120'))
```

View File

@@ -4,6 +4,7 @@
- **Date**: 2026-04-19
- **Deciders**: 統帥
- **Related**: ADR-001三 Agent 分工), ADR-004NemoTron Fallback, ADR-007AI Dual-Write, ADR-011跨專案隔離, ADR-018四 AI Agent 自動化控制面)
- **Note**: [ADR-020](ADR-020-code-review-full-autoheal.md) 局部覆寫本 ADR 對「post-deploy code review pipeline」場景的 L3 HITL 規定 — 該場景改採全自動修復 + Git/CI/CD 回滾安全網。本 ADR 對 schema migration / 流量切換 / customer-facing 廣播 / AIOps prod SSH 等其他 L3 場景仍生效。
## Context

View File

@@ -30,7 +30,7 @@ Exception → Incident(DB) → PlayBook 匹配 → Auto-Heal 執行 → HealLog(
| `services/auto_heal_service.py` | Service | 核心引擎(分類、匹配、執行、沉澱) |
| `database/manager.py` | 修改 | 加入 `_init_autoheal_tables()` |
| `scheduler.py` | 修改 | 三個核心任務植入 `handle_exception` |
| `requirements.txt` | 修改 | 加入 `paramiko` |
| `utils/ssh_helper.py` | Helper | 共用 CLI `ssh` 執行層,供 AutoHeal / AiderHeal 使用 |
### PlayBook 動作類型
@@ -60,7 +60,7 @@ Exception → Incident(DB) → PlayBook 匹配 → Auto-Heal 執行 → HealLog(
## 取捨
**優先使用 paramiko** 而非 subprocess + CLI ssh,原因是在容器內環境控制更精準,且支援跳板機 ProxyJump。若 paramiko 未安裝則自動降級到 CLI ssh向後相容
2026-05-13 實作修訂:現行程式碼已標準化到 `utils/ssh_helper.py`,以 CLI `ssh` + `ProxyJump` 參數組裝執行AutoHeal 與 AiderHeal 共用同一層;因此 `paramiko` 不再是 runtime 依賴。若未來要重新引入 Paramiko必須同時補回 helper 實作、requirements 與回歸測試
---

View File

@@ -21,6 +21,16 @@ Phase 3e4/28-29完成 app.py 7,386→6,590 行(-10.8%),但**僅完
| 模板統一 | ~50% | 三目錄並存 + 1 空檔 + 3 死檔 + 2 TemplateNotFound 風險 |
| DB schema vs Model | ~60% | manager.py import 漏 3 模組6 張表有 SQL 無 ORMrealtime_sales_monthly 孤兒 |
## 實作狀態補記2026-05-13
上表是 2026-04-29 立案時的盤點基線;後續整改已把多個 HIGH 項目落地並加上回歸守門:
- `app.py` 已收斂為 Flask bootstrap / Blueprint registration / 啟動自檢active `@app.route` 為 0並由 `tests/test_phase3f_cleanup_contracts.py::test_app_py_stays_blueprint_only_for_routes` 守住。
-`USE_MODULAR_ROUTES``register_blueprints()``MODULAR_ENDPOINTS`、duplicate cleanup shim 已移除;`routes/__init__.py` 僅保留 package docstring。
- DB metadata / migration 覆蓋已由 `tests/test_migration_metadata_coverage.py` 與啟動自檢守住v5 observability / Market Intel 等表不再只靠手動口述。
- 模板路徑已收斂為 `templates/``web/templates/vendor_stockout/`;根層 placeholder `templates/list.html` 已刪除並有測試防回歸。
- 大檔治理仍未結案:`routes/openclaw_bot_routes.py``routes/admin_observability_routes.py``routes/sales_routes.py``scheduler.py` 仍超過 800 行,後續只能做 bugfix、安全修補或往外抽模組。
## 決策
執行 **Phase 3f 五階段收尾**,總工期估 12-15 小時(不含驗證),每階段獨立 commit、每階段 critic 審查、每階段先 SSH 驗證 production。

View File

@@ -0,0 +1,95 @@
# ADR-020: Code Review 全自動修復政策(覆寫 ADR-012 對 code review 的 HITL 限制)
- **Status**: Accepted
- **Date**: 2026-05-02
- **Deciders**: 統帥
- **Related / Supersedes**: 局部覆寫 ADR-012Agent Action Ladder L3 HITL對「post-deploy code review pipeline」場景的人工審查門檻不影響 ADR-012 對其他 L3 場景(如 schema migration、production restart、telegram broadcast的 HITL 規定
- **Affects**: `services/code_review_pipeline_service.py``services/aider_heal_executor.py``.env.example`、Gitea CI/CD 部署 env
## Context
ADR-012 把所有「實際修改程式碼」的動作劃為 L3預設要求 Human-In-The-Loop 審查。`services/code_review_pipeline_service.py` 依此規則實作四道閘門:
1. `AUTO_FIX_ENABLED` env 預設 `false`
2. EA prompt 寫死「CRITICAL/HIGH → auto_fix=false」
3. Rule fallback `priority not in {critical, high}` 才允許 auto_fix
4. `_guard_ea_decision``has_high_risk` override即使 LLM 回 auto_fix=true 也擋下
**結果**2026-05-02 17:38 commit `52c06f6` 觸發 code review找到 1 CRITICALroutes/openclaw_bot_routes.py 缺 ALLOWED_USERS 空集處理)+ 1 HIGH`_is_authorized` 複雜度過高Telegram 通知顯示「⚠️ Elephant AlphaCRITICAL 👁 需人工審查」——但統帥的政策一直是「全自動修復、Git+CI/CD 為回滾安全網」。
**根本衝突**
- ADR-012 假設「程式碼修改 = 高風險 = 必須人工」
- 統帥實際立場「Code review 找到的都應該全自動修,安全網不是人,是 Git revert + Gitea CI/CD」
- 過去 memory 引述為「ADR-014」是筆誤ADR-014 實為 PPT 系統)
## Decision
**對 post-deploy code review pipeline 場景**,覆寫 ADR-012 的 HITL 規定:
### 四條規則
| # | 規則 | 實作位置 |
|---|------|---------|
| 1 | 任何 findingCRITICAL/HIGH/MEDIUM/LOW一律 `auto_fix=true` | `_ea_orchestrate` prompt + rule fallback |
| 2 | `_guard_ea_decision` 不再依 severity 決定 auto_fix只受 `CODE_REVIEW_AUTO_FIX_ENABLED` 主開關控制 | `_guard_ea_decision` |
| 3 | `CODE_REVIEW_AUTO_FIX_ENABLED` 預設值改為 `true`(過去是 `false` | `services/code_review_pipeline_service.py:43` + `.env.example:187` |
| 4 | Telegram 通知文案移除「需人工審查」,改顯示「自動修復未啟用(旗標)」或「已觸發 AiderHeal」 | `_notify_complete` |
### 安全網(取代 HITL
| 層級 | 機制 | 觸發點 |
|-----|------|-------|
| 1 | AiderHeal 限流:每次最多修 2 個檔案 / 至多 5 個 fix_files | `_trigger_aider_heal:457``_nemotron_dispatch fix_files[:5]` |
| 2 | 修復產生的 commit 走 Gitea Action CI/CD pipeline測試失敗自動拒絕 merge | `.gitea/workflows/cd.yaml` |
| 3 | CD 健康檢查不過 → compose up 失敗 → 服務維持舊版本 | ADR-008 / ADR-010 |
| 4 | Git 歷史完整保留,`git revert <sha>` 一行回滾 | 標準 git 流程 |
| 5 | 主開關 `CODE_REVIEW_AUTO_FIX_ENABLED=false` 可即時切斷整條鏈(不需 redeploy 程式碼) | env var |
### 邊界(不影響的場景)
ADR-012 的 HITL 規定**仍對下列場景生效**,本 ADR 不覆寫:
- Schema migration / DB 結構變更
- Production 服務重啟、流量切換
- Telegram 廣播訊息(用戶可見)
- 任何牽涉 customer-facing data 的 mutation
- AIOps AutoHeal 對 production 主機的 SSH 修復動作ADR-013
換言之:本 ADR 只對「post-deploy 的 code review → AiderHeal → 提 commit → CI/CD 自動回測」這一條閉環給綠燈。
## Alternatives Considered
| 方案 | 為何不選 |
|------|---------|
| A. 維持 ADR-012 HITL用 Telegram 按鈕做 one-click approve | 統帥多次表態「不要人工審查」,且 17:38 截圖顯示 Telegram 出現 HITL 訊息就是引爆點 |
| B. 全部 ADR-012 場景都改全自動 | 風險面過大schema migration / 流量切換不適用「Git revert」這種事後回滾 |
| C. 用 severity 切MEDIUM/LOW 自動、CRITICAL/HIGH 仍 HITL | 即現況;統帥明確指出「之前的 HIGH 1-2 → 人工審查門檻是錯誤的」 |
| D. 留 HITL 但加「24 小時無人回應自動 fix」timer | 引入時間視窗複雜度,且仍不符「全自動」的精神 |
## Consequences
### 正面
- Code review pipeline 真正端到端自動化,符合統帥對 AI Agent 的期待
- HITL 通道清空Telegram 訊息聚焦「修復進度」而非「等你決定」
- AiderHeal 修復頻率提高 → 觸發更多 OpenClaw learning data符合 ADR-007 雙寫)
### 負面 / 風險
- AiderHeal 誤判機率提高時,會在 main 留下需 revert 的 commit雖然 CI/CD 會擋住部署,但歷史會有雜訊)
- 主開關 `CODE_REVIEW_AUTO_FIX_ENABLED` 變成關鍵 env誤設 false 會悄然斷掉整條鏈
- ADR-012 文件需註解「ADR-020 已局部覆寫」(待後續 commit 補上)
### 監控指標
- `ai_insights.metadata_json.auto_fix_triggered=true` 比例(部署後應 → 100% 在有 finding 時)
- AiderHeal 後 CI/CD 失敗率(觀察 1 週,>30% 要重新評估)
- `git revert` 頻率(>每週 1 次代表 AiderHeal 品質有問題)
## 實作 checklist
- [x] `services/code_review_pipeline_service.py` 拆四道閘
- [x] `.env.example` 預設 true
- [x] `tests/test_code_review_pipeline_security.py` 反轉 HITL 期望(含 LLM 降級被 guard 拒絕的測試)
- [x] `docs/adr/README.md` 索引加 ADR-020
- [x] `docs/adr/ADR-012-agent-action-ladder.md` 加反向引用註記(**Note** 行)
- [x] `services/aider_heal_executor.py` 標頭從「ADR-014」更正為「ADR-020」並補分支策略說明
- [x] Memory `feedback_code_review_autoheal.md` ADR 號碼從「ADR-014」改為「ADR-020」
- [ ] 188 / Gitea env 設 `CODE_REVIEW_AUTO_FIX_ENABLED=true`(程式碼預設已 true此 env 為冗餘保險,部署時統帥決定)

View File

@@ -0,0 +1,130 @@
# ADR-021: EA HITL Pre-fetch + 競價告警必填金額影響量化
- **Status**: Accepted
- **Date**: 2026-05-03
- **Deciders**: 統帥
- **Related**: 補強 ADR-012Agent Action Ladder L3 HITL對 escalation 訊息內容的要求;不取代任何既有 ADR
- **Affects**: `services/elephant_alpha_autonomous_engine.py``services/nemoton_dispatcher_service.py``services/hermes_analyst_service.py``services/telegram_bot_service.py`
## Context
2026-05-02 統帥收到一條 EA 升級審核 Telegram 告警commit `b5a2b094` 時段),內容為:
> 自主決策信心度 0.83 低於門檻,需人工批准
> AI 摘要:競爭對手價格溢價 >5% 且有庫存充足…
> 步驟 1[OpenClaw] 基於市區拉貨區市場特性,生成包含動態定價模型與競爭對手分析的策略建議
> 步驟 2[Hermes] 識別具體競爭商品並量化價格差異(目標確認至少 20 個高價溢價 SKU
> 步驟 3[NemoTron] 將生成的定價策略與競爭分析結果同步至人工審核管道
統帥指出此告警**毫無決策價值**,原因:
1. 沒有具體 SKU、沒有金額影響、沒有可批准/駁回的具體動作
2. 三步驟「建議行動」實為「申請開始分析」的元流程描述OpenClaw 生成策略 → Hermes 識別 SKU → NemoTron 同步),人類審核者沒有判斷依據
3. HITL 攔截點放錯位置:應在「具體動作出爐後、執行前」攔,而非「分析計畫產出但尚未跑」
### 程式碼層證據
**根因 A — `_escalate_to_human` 的 ai_actions 來源是 plan 階段**[`services/elephant_alpha_autonomous_engine.py:528-557`](services/elephant_alpha_autonomous_engine.py#L528-L557) 的 `_execute_autonomous_decision``elephant_orchestrator.analyze_and_coordinate` 產出 `StrategicDecision` 後,**信心度不足即 escalate**——此時 `decision.execution_plan` 還只是 Gemini 寫的 plan 文字Hermes/NemoTron 從未實際跑過取得具體 SKU。`_escalate_to_human` 把 plan 的前 3 個 step description 直接灌進 `triaged_alert.ai_actions` 是空泛元流程的根源。
**根因 B — Hermes/NemoTron 已有具體告警,但缺金額影響量化**[`services/nemoton_dispatcher_service.py:683-700`](services/nemoton_dispatcher_service.py#L683-L700) 的 `_exec_trigger_price_alert` 已經能輸出「[SKU] 商品MOMO $X / PChome $Y價差 ±%|銷量 ±%」,但**缺絕對金額影響**——人類看到「價差 22.4%、銷量 -35%」仍需自己換算「我這週實際少賺多少」才能決策。
**根因 C — `momo:eig:` callback 按鈕從未實作**[`services/telegram_templates.py:466-467`](services/telegram_templates.py#L466-L467) 的 `triaged_alert` 鍵盤產出「🛑 忽略此事件」按鈕callback_data = `momo:eig:{event_id}`),但 [`services/telegram_bot_service.py:512`](services/telegram_bot_service.py#L512) 的 `handle_callback` 只 dispatch `menu:/cmd:/await:` 三個 prefix**`momo:` prefix 完全沒處理**——統帥點擊忽略按鈕後永遠沒反應HITL 流程閉環缺一環。
## Decision
對 EA L3 HITL 升級審核訊息與 NemoTron 競價告警採取三項根治措施:
### 規則 1 — EA 升級審核 pre-fetch Hermes 具體威脅清單
`_PRICE_RELATED_TRIGGERS = {price_drop_alert, market_opportunity, threat_escalation}` 三類觸發,`_escalate_to_human` **送 Telegram 前先呼叫 Hermes 取得具體 SKU 清單**,將前 5 筆格式化為:
```
[SKU] 商品名稱MOMO $X vs PChome $Y (±%)|近 7 日流失 NT$ Z建議跟進 NT$ W
```
蓋掉原本的 plan 元流程文字。**強制配套限制**
- `asyncio.wait_for(timeout=5)` 短超時Hermes 熱駐留 < 10s但冷啟動會拖到 30s+HITL 訊息延遲不可大於 10s
- Pre-fetch 失敗timeout / 0 threats / 全部缺金額)→ **不送 Telegram、不寫 pending human_review**,只記錄 suppressed escalation telemetry 與 cooldown避免把無實證 plan 當成可審核告警
- 「全部行皆缺金額」也視同無料 fallback避免「乾巴巴兩行 MOMO/PChome 比價」比 plan 文字更空泛
### 規則 1.1 — 非價格類低信心 escalation 必須有可審核內容
2026-05-19 補充:`resource_optimization` 不是 SKU/價格事件,不能套用 Hermes/SKU fallback 模板。當 EA 對 `resource_optimization` 只產出低信心決策且沒有具體可審核行動時,系統只記錄 telemetry 與 cooldown不發 Telegram也不建立 `ai_insights.status='pending'` 的人工審核。這避免「資源調配優化」告警顯示「Hermes 即時威脅清單不可用」這類錯誤診斷。
### 規則 2 — NemoTron 告警必填金額影響量化
新增模組級 helper `_compute_business_impact(threat) -> {revenue_loss_7d, recommended_price}`
- **`revenue_loss_7d`** = `max(0, sales_7d_prev_amount - sales_7d_curr_amount)` 且**僅在 `gap_pct > 0` 時計算**
- 語意:「我方比競品貴,且過去 7 日銷量金額下滑 → 推估價格因素導致的流失」
- `gap_pct ≤ 0`(我方便宜或持平)即使銷量下滑亦歸 0避免把季節性/商品壽命終結等非價格因素誤標為「流失」誘導降價
- **`recommended_price`** = `round(pchome_price)``gap_pct > 0`;否則 `None`
- 語意:「跟進競品的最低調價金額」;統帥可基於此再依毛利策略加溢價
`_fmt_price_alert` / `_fmt_human_review` 加入「📉 過去 7 日營收流失NT$ X」「🎯 跟進競品建議價NT$ Y毛利策略可再加溢價」區塊。dispatch() 主路徑、防線二強制覆核、`_hermes_rule_fallback` 三條路徑**全部走 Python 獨裁注入**(同 Bug-1 防線二原則:客觀數字不過 LLM
為支援此計算,`PriceThreat` dataclass 新增 `sales_7d_curr_amount` / `sales_7d_prev_amount` 兩個欄位,由 `_batch_analyze` 從 SQL 結果直接帶出(**不**餵給 LLM 推理,避免 token 爆炸與 LLM 嘗試引用幻覺)。
### 規則 3 — 補實 `momo:eig:` callback handler
`telegram_bot_service.py.handle_callback` 在既有 `menu:/cmd:/await:` dispatch 之前加 `momo:eig:` 處理,呼叫 `_handle_event_ignore_callback`
1. 解析 `event_id`**空 id 立即拒絕**(防 audit 污染)
2. 寫入 `ai_insights``status='ignored', insight_type='human_review', metadata_json``event_id / decided_by / decided_at`ADR-012 §③ audit trail
3. 編輯原訊息加「🛑 已忽略 by `<user>` @ `<ts>`」尾註
4. **`user_label` / `ts_label` 寫入 HTML 前必須 `html.escape()`**user-controlled Telegram username 透過 `<a href>/<pre>` 注入超連結與破版的 XSS 防線)
5. 任何例外都 best-effort不阻斷 UI
### Critic 審查(必修)
| 編號 | 嚴重度 | 內容 | 修復 |
|------|--------|------|------|
| Critical-1 | CRITICAL | `user_label` 直接 HTML 拼接 → username 注入 `<a>/<pre>` 破版 | `html.escape()` 雙重 escape |
| High-1 | HIGH | Pre-fetch Hermes 同步阻塞 escalation cooldown 視窗30-60s | `asyncio.wait_for(timeout=5)` |
| High-2 | HIGH | Hermes 有 threats 但全部缺金額時 → 兩行乾巴巴比價反而更空泛 | `any_concrete` 判斷,全缺則 `return None` 觸發 plan fallback |
| Medium-2 | MEDIUM | 空 `event_id` callback 寫入 `'unknown'` 污染 audit | prefix 解析後即拒絕 |
| Medium-3 | MEDIUM | `gap_pct ≤ 0``prev > curr` 仍顯示「流失」誤導降價 | `revenue_loss_7d` 條件改為 `if gap_pct > 0` |
## Alternatives Considered
| 方案 | 為何不選 |
|------|---------|
| A. 廢掉 `market_opportunity` 觸發類型,全交 NemoTron pipeline | EA 同時負責 `price_drop_alert / threat_escalation / resource_optimization / code_exception` 多類觸發,不可單刪一類;且 EA orchestrator 是 SOT廢觸發類型需大改 |
| B. 把 EA 信心度門檻降到 0.5讓「market_opportunity」全部自主執行 | 違反 ADR-012 L3 HITL 對「實際修改價格」的安全網;統帥未授權自動調價 |
| C. Pre-fetch 改為背景 taskescalation 訊息分兩次發 | 兩次告警分裂語境,使用者體驗差;且 Hermes 結果晚到時 escalation 已 cooldown |
| D. 不 pre-fetch要求人類自己用 `/menu` 查 SKU | 違反「告警必須 actionable」精神且增加人類認知負荷 |
## Consequences
### 正面
- EA 升級審核 Telegram 內容從元流程描述變為「具體 SKU + 價格 + 金額流失 + 建議調價」HITL 真正可決策
- 無實證的價格類與資源調配低信心 escalation 不再打擾人工,避免 Telegram 出現不可批准、不可駁回、不可操作的空告警
- NemoTron 既有告警再升級,每筆都帶可批准/駁回的金額判斷依據
- `momo:eig:` 按鈕首次有對應 handlerHITL 流程閉環完整
- pre-fetch 改用 5s 短超時 + fallback最壞情況退回原 plan 文字,不破壞既有行為
### 負面 / 風險
- 每次價格類 escalation 多花 ≤ 5sHermes 熱駐留實測 < 10s 但有 timeout整體告警延遲略增
- Hermes 在 5s 內若沒回應,價格類 escalation 會被壓制並記錄 telemetry若後續需要追查需從 `ai_calls.meta.suppressed_escalation` 與 scheduler log 觀察
- `gap_pct ≤ 0` 案例的銷量下滑(非價格因素)將完全不顯示流失金額——若統帥需追蹤「非價格流失」需另開告警類型(待後續 ADR
### 監控指標
- Telegram 「EA 升級審核」訊息含「📉 過去 7 日營收流失」比例(部署後應 → 每筆價格類觸發都有,除非 5s timeout
- `_handle_event_ignore_callback` audit 寫入頻率(觀察人類實際使用 HITL 比例)
- Hermes pre-fetch timeout rate>10% 代表 Ollama 冷啟動嚴重,需檢查 keep_alive
## 實作 checklist
- [x] `services/hermes_analyst_service.py` PriceThreat 新增絕對金額欄位
- [x] `services/nemoton_dispatcher_service.py` `_compute_business_impact` helper + 三條 dispatch 路徑注入
- [x] `services/elephant_alpha_autonomous_engine.py` `_fetch_hermes_threats_summary` + 5s timeout + fallback
- [x] `services/telegram_bot_service.py` `_handle_event_ignore_callback` + HTML escape + 空 id 拒絕
- [x] 2026-05-19無實證價格類 / `resource_optimization` 低信心 escalation 改為 suppressed telemetry不再送空泛 Telegram
- [x] Critic 審查通過Critical-1 / High-1 / High-2 / Medium-2 / Medium-3 全修)
- [x] Smoke test`_compute_business_impact` 對 gap≤0 / gap=0 / 銷量回升 / bogus type 四案例驗證
- [x] `docs/adr/README.md` 索引加 ADR-021
- [ ] 部署到 188 + 觀察首日 EA escalation 內容(人工驗證)

View File

@@ -0,0 +1,120 @@
# ADR-022: PPT 簡報系統 v3 — 暖紙風 + matplotlib 專業圖表 + 模板版本快取
- **Status**: Accepted
- **Date**: 2026-05-02 / 03
- **Deciders**: 統帥
- **Related**: 取代 ADR-014 中的 PPT 視覺/結構描述V2 → V3不影響 V2 既有「6 種報告 vs 9 種報告」校正growth/vendor/bcg 仍未落地)
- **Affects**: `services/ppt_generator.py``routes/openclaw_bot_routes.py``Dockerfile``scripts/ppt_cleanup.sh`
- **Commit chain**: `38967ce``3b0b4b3``52c06f6``1c81866``b5a2b09``c7b7cee``92b8035``5a7012f`
## Context
2026-05-02 統帥檢視月報V2後指出五項視覺品質缺陷
1. 圖表醜python-pptx 原生柱狀圖無資料標註、無顏色分級)
2. 熱銷商品只 10 品(用戶要求 50 品)
3. 專案 RAG 情報內容太陽春(單一 textbox 顯示靜態節日字串)
4. 排版亂封面大面積暖墨黑、AI 頁深色 + 白字過於濃重)
5. 字體未對齊設計系統(中英混排撞 Courier New
並要求對齊「市場上專業日報/週報/月報」的標準McKinsey/BCG 等級顧問報告)。
第一輪重做後又抓出三類延伸需求:
- 同份 PPT 可秒回cache但模板升版時舊 cache 必須自動失效
- AI 分析內容要詳盡且專業,能直接幫銷售/行銷做決策參考
- 容器 CJK 字型必須真正能渲染中文
## Decision
### A. 視覺重做 — 暖紙風(取代暖墨黑)
**封面**`_BG_PAPER (#F3EEE2)` 米紙底取代 `_BG_DARK (#2A2520)`,焦糖橘左寬條 + 暖墨色標題。
**KPI 卡v2**value 大字含右下角 △% 徽章(綠↑紅↓),含 `delta_label="vs 上月"` / inverse 反轉模式(用於成本類指標)。
**字型分軌**:透過 lxml 直寫 `<a:latin>`+`<a:ea>` (`_set_run_fonts`),數字/英文走 Consolas點陣等寬感中文走 Microsoft JhengHei。`_insert_rpr_child` 依 ECMA-376 §21.1.2.3 順序插入子元素(避免 LibreOffice/Keynote 拒絕讀取)。
### B. 圖表升級 — matplotlib 暖色系(取代 python-pptx 原生)
| Helper | 用於 | 特色 |
|---|---|---|
| `_mpl_horiz_bar_png` | 月報品類橫條 | TOP3 焦糖橘 / 4-6 蜂蜜金 / 7+ 焦土,條右標 NT$X.X萬+佔比% |
| `_mpl_line_chart_png` | 日/週/月趨勢 | 本月實線+上月虛線+日均水平線+高低點標註N≤2 sparse 防呆 |
| `_mpl_pareto_chart_png` | 月報品類雙視圖 | 業績條80% 主力焦糖橘)+ 累計%曲線+80% 主力線 |
容器 CJK fallback`fonts-noto-cjk` 套件 ttc 檔在 matplotlib `font_manager.ttflist` 只認 `Noto Sans CJK JP` 變體,但 ttc 內漢字字型表共用,可正常渲染中文。`_mpl_setup` fallback 列表必須包含 `Noto Sans CJK JP`
### C. 模板版本快取template_version cache invalidation
```python
# services/ppt_generator.py
TEMPLATE_VERSIONS = {
'monthly': 'v3.1.3',
'daily': 'v3.0.2',
...
}
# routes/openclaw_bot_routes.py
def _normalize_ppt_parameters(parameters):
"""自動把 tpl_ver 注入 cache key"""
params['tpl_ver'] = get_template_version(report_type)
return json.dumps(params, sort_keys=True)
```
**Bump 規則**major 設計改版 +0.1(如 v3.0 → v3.1);補丁修正 +0.01v3.1.1 → v3.1.2。bump 即觸發舊快取自動 miss。
**緊急清空**`_invalidate_ppt_cache(report_type=None)` Python helper / `/cache flush` Telegram 指令admin only
**磁碟清理**`cleanup_expired_ppt_cache(days_old=7, dry_run=True)` — 安全預設 dry_run=True呼叫方明確傳 False 才實刪。launchd plist 排程每日 03:15 跑macOS 開發機)。
### D. AI prompt 升級到顧問深度
**月報 prompt 升級**`_ppt_ai_analysis`
- 角色BCG/麥肯錫策略顧問 + momo 行銷主管 + 品類採購(三合一)
- 必含「市場趨勢脈絡」段:當期檔期 + 2026 熱門賽道(永續美妝/母嬰高端/敏弱肌/銀髮保健等)+ 平台競爭(蝦皮/PChome/酷澎)
- 行動建議走 SMART 框架Specific/Measurable/Achievable/Relevant/Time-bound分本週/本月/下月三層
- 禁用「可能/也許/建議考慮」等模糊用詞
- 字數 900-1200max_tokens 2400
**AI 段落 parser**`_parse_ai_sections`):丟掉空 body 段(避免顯示「本段無內容」);上限 6→10 容納 SMART 9 段。
### E. 安全機制 — admin 白名單 + dry_run 預設
- **`OPENCLAW_ADMIN_USER_IDS` 環境變數**`/cache flush``/cache cleanup confirm` 限管理員執行;未設時退回 ALLOWED_USERS向後兼容 fail-closed
- **`_CURRENT_USER_ID_CTX` ContextVar**webhook 入口msg + callbacksethandle_cmd 讀取,避免改 30+ 處呼叫端簽名
- **cleanup days<1 強制乾跑**(防呆)
## Consequences
### Positive
1. **視覺對齊市場專業標準**:與 McKinsey/BCG 月度報告一致的暖紙風+圖表標註+帕雷托雙視圖
2. **模板升版零阻力**bump TEMPLATE_VERSIONS 即生效,無需手動清快取
3. **記憶體穩定**matplotlib helpers 全部 try/finally 包好,渲染失敗不洩漏 figure
4. **AI 內容可實戰**:每段含具體商品名+量化目標+期限BU 主管可直接做決策
5. **容器化部署**Dockerfile 加 `fonts-noto-cjk`CI/CD 自動帶字型
### Negative
1. **月報 cache miss 路徑變慢**cache miss 時連續查 current/prev_month/prev_year 三次12 SQL延遲 3×。命中後正常同份秒回
2. **PPT 檔變大**matplotlib PNG 取代原生 chart月報 130KB → 326KB含 3 張高品質圖)
3. **`fonts-noto-cjk-extra` 增加 ~100MB image 大小**:可瘦身但 trade-off 字型完整度
### Risks Mitigated
- **figure 洩漏 → OOM**try/finally 修復critic HIGH-1
- **靜默實刪災難**cleanup 預設 dry_run=Truecritic HIGH-2
- **群組成員誤觸破壞性指令**admin 白名單critic Medium-3
- **未來改讀模板 .pptx schema 違反**`_insert_rpr_child` 維護順序critic Medium-1
## Alternatives Considered
1. **保留 python-pptx 原生 chart**:拒絕 — 原生不支援資料標註、顏色分級無法做到 BCG 級觀感
2. **用 hash(ppt_generator.py 內容)[:8] 自動 cache key**:拒絕 — 改個 typo 也 invalidate 全部,過度敏感
3. **改 handle_cmd 簽名加 user_id**:拒絕 — 30+ 處呼叫端要動,風險大;用 ContextVar 更乾淨
## References
- Critic 完整審查報告:見 commit `38967ce` 之後的 critic agent run
- 實戰驗證:在 188 prod 容器內生成 monthly v3.1.3AI 內容 3 頁全 SMART 行動建議
- 原 ADR-014V2 PPT未廢止但視覺/結構/cache 部分由本 ADR 取代

View File

@@ -0,0 +1,117 @@
# ADR-023: PPT 系統 Wave 1 擴展 — 廠商 / 期間回顧 / 品類深度 / 客戶分析
- **Status**: Accepted
- **Date**: 2026-05-03
- **Deciders**: 統帥
- **Related**: 延續 ADR-022PPT v3 暖紙風 + 模板版本快取機制),擴展 4 + 4 = 8 種新報表類型
- **Affects**: `services/ppt_generator.py``routes/openclaw_bot_routes.py``services/openclaw_bot/menu_keyboards.py`
- **Commit chain**: `b6fdb4f` (vendor) → `1af96f5` (period_review × 4) → `d8260fc` (category) → `48e3dac` (customer)
## Context
統帥盤點現有 6 種 PPT 報表daily/weekly/monthly/strategy/competitor/promo後指出市場上專業 BI 報告還有大量缺口:
1. 季報 / 半年報 / 年報 / TTM 滾動 12 月(時間維度)
2. 廠商業績報告(採購視角)
3. 品類深度報告PM/採購視角)
4. 客戶/訂單分析(行銷視角)
5. 競業/競品行銷比較(升級 competitor
6. 市場公開報告彙整週報
7. 等共 17 種
並批准全部執行。Wave 1 聚焦最高 ROI 的 4 種vendor、period_review、category、customer優先做完。
## Decision
### A. 共用 Generator 設計period_review 一份解 4 種)
`generate_period_review_ppt(period_type, period_label, db_data, ai_text)` 用一份程式碼處理:
- `quarterly` (2026 Q1)
- `half_yearly` (2026 H1)
- `annual` (2026)
- `ttm` (TTM 2025-05~2026-04)
差異僅在路由層的時間範圍計算 + 封面徽章顏色。**省 60%+ 程式碼**。
### B. 8 種新報表全部 v3.1.0 上線
| 類型 | 函式 | 頁數 | 角色 | 核心特色 |
|---|---|---|---|---|
| vendor | `generate_vendor_ppt` | 8 | 採購主管 | 集中度警示 + 帕雷托議價優先 |
| quarterly | `generate_period_review_ppt('quarterly')` | 12 | BU 主管 | QoQ + YoY 三段比對 |
| half_yearly | 同上period_type='half_yearly') | 12 | BU 主管 | HoH + YoY |
| annual | 同上period_type='annual') | 12 | CEO/CFO | 年度 + 前年比對 |
| ttm | 同上period_type='ttm') | 12 | 財務 | 滾動 12 月去除季節性 |
| category | `generate_category_deep_ppt` | 12 | PM/採購 | 90 天 + 子品類 + 新進榜CTE |
| customer | `generate_customer_analytics_ppt` | 7 | 行銷主管 | 客單分桶 + 星期分佈 + 復購(簡化 RFM |
### C. AI Prompt 角色化(每種報表配對應角色)
| 報表 | AI 角色 | max_tokens |
|---|---|---|
| vendor | 採購主管 + 供應鏈管理顧問 | 1800 |
| period_review | 策略顧問 + BU 主管 + CFO 三合一 | 2600 |
| category | 採購主管 + PM 商品經理 | 1800 |
| customer | 資深行銷主管RFM/CRM | 1500 |
每個角色都引用 `MARKET_TREND_2026` 共用知識基底,跨報表敘事一致。
### D. 資料層擴充4 個新 query 函式)
| 函式 | 用途 |
|---|---|
| `query_vendor_summary(start, end, lim)` | 廠商業績聚合含毛利、qty、orders|
| `query_period_summary(start, end)` | 期間綜合kpis + monthly_breakdown + top_*|
| `query_category_deep(category, days)` | 單品類縱向(含 sub_categories L2 + new_products CTE|
| `query_customer_analytics(start, end)` | 訂單級分析AOV bucket + DOW + 復購)|
### E. Customer 報表的限制聲明
`realtime_sales_monthly` 表無 `user_id` 欄位PII 法規),無法做完整 RFM。**封面與 prompt 都明確聲明此限制**,並建議「日後接入會員系統 user_id → 可升級完整 R/F/M 11-persona 分群」。
### F. Telegram 按鈕擴充
`_submenu_reports()` 從原 7 顆按鈕擴充到 14 顆:
- 既有:日/週/月、策略 5 種、促銷、競品、指定日期/月份
- 新增廠商、季報、半年報、年報、TTM、品類深度、客戶分析
## Consequences
### Positive
1. **角色化覆蓋完整**採購vendor/category/ BU 主管period_review/ 行銷customer/promo/ CEOannual/ttm/ PMcategory每個高層都有對應的 BI 報表
2. **共用 Generator 大幅省工**period_review 用 1 份函式解 4 種,未來新增「半月報」「兩月報」等只需加路由分支
3. **資料層復用**4 個新 query 函式都基於同一張 `realtime_sales_monthly`,無需新建 table
4. **AI 跨報表敘事一致**MARKET_TREND_2026 共用常數確保所有 AI 用同一份市場事實基底
### Negative
1. **Cache miss 路徑變慢**period_review 一次要拉 3 段資料(本期 / 上期 / 去年同期),每段 4 條 SQL共 12 條
2. **PPT 變大**12 頁含 3-4 張 matplotlib PNG每份 200~330KB
3. **菜單按鈕 14 顆**:可能略顯擁擠,未來考慮分子選單
### 風險與緩解
- **vendor 集中度判定誤差**:用前 N 家佔 80% 的比例 / 總家數判斷極端值5 家全部 = 100%)會誤判。已加 `if vcount` 防呆。
- **TTM 月份切割**CURRENT_DATE 在月初與月末判定不同。已用 `replace(day=1)` 對齊月初。
- **customer 復購率失真**:因無 user_id「商品復購」實為「同商品被多筆訂單購買」並非「同一客戶重複購買」。已在 prompt 與封面註腳聲明。
## Alternatives Considered
1. **每種報表各寫獨立 generator**:拒絕 — 會產生 4 份高度相似的 600+ 行函式,維護成本高
2. **完整 RFM 11-persona 分群**:拒絕 — 資料層無 user_id 強做會誤導決策;改先做訂單級簡化版 + 註明日後升級路徑
3. **bcg generator 升級到 v3**:拒絕 — 與 strategy 功能重疊strategy 已含 BCG 思路),保留待 ADR-024 廢除
## Wave 2 / Wave 3 / Wave 4 待辦
依 17 種完整清單,本次完成 Wave 14 種)+ period_review 共用解 4 種 = 8 種。剩餘:
- **Wave 2**: competitor v4 五力升級 / promo_compare 多活動比較 / forecast_pre_event 檔期前瞻
- **Wave 3**: market_intel_weekly 外部彙整 / new_product 30 天追蹤 / clv 客戶終身價值 / price_elasticity 價格彈性
- **Wave 4**(依資料層): inventory 庫存健康 / operations 履約 / finance P&L
- **廢除**: bcg generator與 strategy 重疊)
## References
- 對應 memory`reference_ppt_system.md`v3 → v3.1 擴展)、新建 `project_ppt_v3_wave1_expansion_20260503.md`
- 商業價值排序vendor > category > customer > period_review依 ROI
- 全 14 種 PPT 報表清單daily / weekly / monthly / quarterly / half_yearly / annual / ttm / strategy / competitor / promo / vendor / category / customer + 廢除中的 bcg

View File

@@ -0,0 +1,118 @@
# ADR-024: PPT 系統 Wave 2 — 檔期前瞻 / 多活動比較 / bcg & growth 廢除
- **Status**: Accepted
- **Date**: 2026-05-03
- **Deciders**: 統帥
- **Related**: 延續 ADR-023Wave 1 擴展),補上 Wave 2 的 2 種前瞻型報表,並正式廢除 bcg / growth
- **Affects**: `services/ppt_generator.py``routes/openclaw_bot_routes.py``services/openclaw_bot/menu_keyboards.py`
- **Commit chain**: `9f04dc3` (forecast) → `958f705` (promo_compare)
## Context
延續 ADR-023 Wave 1 完成 4 種報表後Wave 2 鎖定「前瞻決策型」報表 — 給 BU 主管在事件**發生前**做戰術部署,而非事後復盤。
兩個 Wave 2 報表:
1. **forecast_pre_event** — 檔期前 14 天的備戰策略
2. **promo_compare** — 多場促銷活動的 ROI 橫向比較(覆盤學習)
同時正式廢除 2 個從未落地或已被取代的 generator。
## Decision
### A. forecast_pre_event 檔期前瞻
**價值**BU 主管在母親節 / 618 / 雙11 等大檔期前 14 天觸發,得到:
- 預期業績baseline 日均 × 21 天 × `lift_factor`
- 去年同檔期實績作為基準線
- 已執行進度(檔期前已過 N 天的累積業績 vs 預期)
- baseline 期 TOP 30 商品作為庫存盤點對象
**核心算法**
```python
baseline_period = [event_date - 60d, event_date - 30d] # 去除檔期前期效應
last_year_period = [event_date_LY - 7d, event_date_LY + 7d]
prep_window = [event_date - 14d, event_date + 7d]
expected_revenue = baseline.avg_daily * 21 * lift_factor[event_name]
```
**靜態 lift_factor 知識**(依台灣電商歷史經驗):
| 檔期 | Lift |
|---|---|
| 雙11 | 1.65× |
| 農曆年 | 1.50× |
| 618 / 黑五 | 1.45× |
| 母親節 / 雙12 | 1.40× |
| 520 / 雙10 / 聖誕 | 1.30× |
| 父親節 / 中秋 | 1.25× |
| 端午 / 婦女節 | 1.20× |
| 勞動節 | 1.15× |
**封面倒數天數徽章**自動切換:備戰期(>7 天)/ 衝刺期≤7 天)/ 檔期中 / 已結束。
### B. promo_compare 多活動 ROI 比較
**價值**:行銷主管覆盤多場促銷活動,找出成功要素與失敗診斷。
**輸入格式**`/ppt promo_compare 母親節:2026/05/05-2026/05/14|520:...|618:...`
`|` 分多場,每場 `label:start-end`
**核心輸出**
- P2 並排 KPI 表(活動/期間/天數/業績/訂單/毛利/業績拉抬/訂單拉抬8 欄
- P3 業績拉抬橫條圖(按拉抬 % 排序TOP3 焦糖橘)
- P4 AI 跨活動洞察:勝出活動成功要素 / 失敗活動診斷 / SMART 三層
### C. 正式廢除 bcg / growth generator
**bcg**
- **理由**:與 strategy 報表功能重疊strategy 已內含 BCG 加碼/機會/收割/觀察五級分類,且支援日/週/月/季/半年/年六種時間範圍)
- **處理**:函式保留作為 internal helper避免破壞既有 importTEMPLATE_VERSIONS 標 DEPRECATED路由未綁定從未綁定UI 無按鈕
**growth**
- **理由**:已被 quarterly + half_yearly + annual + ttm 完全取代period_review 共用 generator
- **處理**:同 bcgDEPRECATED 標記但保留函式
**vendor 不廢除**(之前 v2.0 標 DEPRECATED— 已在 Wave 1 喚醒並升級到 v3.1.0。
## Consequences
### Positive
1. **前瞻型決策補完**:報表體系從「事後復盤」延伸到「事前部署」
2. **檔期戰術可量化**lift_factor 提供具體預測基準,不再憑感覺備貨
3. **跨活動學習機制**promo_compare 把「散落的單一活動效益」變成「可橫向學習的策略矩陣」
4. **報表類型清單收斂**14 種有效 + 2 種 DEPRECATED清楚標記避免誤用
### Negative
1. **forecast lift_factor 是靜態知識**未來如台灣電商檔期生態變化如雙11 拉抬下降到 1.40),需手動 bump
2. **promo_compare 受 query_promo_comparison 速度限制**:每場活動跑一次 SQL未做平行N 場活動 = N 次 query 串行
3. **forecast 跨年判斷邊界**`event_date.replace(year=year-1)` 在 2/29 會拋例外(已 try/except 處理)
### 風險與緩解
- **新進榜 CTE 在低資料量品類失準**`recent EXCEPT early` 對小品類可能誤判(如 30 天前才開的新品類所有商品都「新進榜」)。緩解:保留人工審視(不直接觸發自動化決策)
- **forecast confidence 標記**:去年同檔期無資料時 confidence='low'prompt 內已提醒 AI 降低預測信心
## Wave 3-4 待辦(下次接力)
依 17 種完整清單,本次完成 Wave 2.1 + 2.2 = 11 種有效報表(含 Wave 1 的 8 種、v3 既有的 6 種重做後)+ 2 種 DEPRECATED。剩餘
**Wave 2.3 (跳過下次做)**:
- competitor v4 五力升級(需要外部資料:商品力/行銷力/品牌力/服務力)
**Wave 3**:
- market_intel_weekly 外部彙整週報政府零售業營業額、平台法說、Similarweb、Dcard、Trends
- new_product 30 天追蹤
- clv 客戶終身價值(需 user_id
- price_elasticity 價格彈性
**Wave 4**(依資料層):
- inventory 庫存健康(需 stock 表)
- operations 訂單履約(需 fulfillment 表)
- finance P&L需 finance 表)
## References
- 對應 memory`reference_ppt_system.md`v3.1 → v3.1+ 含 Wave 2 的 2 種新報表)、新建 `project_ppt_wave2_forecast_20260503.md`
- ADR-022: PPT v3 redesign前提
- ADR-023: Wave 1 擴展(前一波)

View File

@@ -0,0 +1,113 @@
# ADR-025: PPT 系統 Wave 3 — 新品追蹤 + 市場情報週報
- **Status**: Accepted
- **Date**: 2026-05-03
- **Deciders**: 統帥
- **Related**: 延續 ADR-023/024補上 Wave 3 兩種 PM/CEO 級報表
- **Affects**: `services/ppt_generator.py``routes/openclaw_bot_routes.py``services/openclaw_bot/menu_keyboards.py`
- **Commit chain**: `95a74c3` (new_product) → `fe3cba8` (market_intel)
## Context
Wave 3 鎖定「橫向資訊整合」型報表:
1. **new_product** — PM 剛需,從現有資料層用 PostgreSQL CTE 抽出新品
2. **market_intel_weekly** — 把 `mcp_collector_service` 所有外部 API 彙整成一份對外可分享的內部簡報
Wave 3 餘下三項受限於資料層或外部依賴:
- clv 客戶終身價值 — 需 user_id無 PII 資料層)
- price_elasticity — 需要長期定價歷史
- competitor v4 五力升級 — 需要外部 SKU/品牌力資料
## Decision
### A. new_product 30 天追蹤
**核心算法**
```sql
WITH recent AS ( 30 ),
early AS (31-90 )
SELECT recent.* FROM recent
LEFT JOIN early ON recent.id = early.id
WHERE early.id IS NULL -- 排除「過去也賣過」的商品
ORDER BY rev DESC LIMIT 50
```
**新品力定位**(業界基準):
| 業績佔比 | 標籤 | 顏色 |
|---|---|---|
| ≥ 8% | 新品力強勁 | 綠 |
| 3-8% | 新品力穩健 | 黃 |
| 1-3% | 新品力偏弱 | 橘 |
| < 1% | 新品力疲弱 | 紅 |
**輸出 9 頁**:封面 / KPI / 整體日業績曲線(爬榜軌跡)/ 品類分佈 / TOP 50 / AI / 附錄。
### B. market_intel_weekly 外部彙整
**整合 8 個外部資料源**
1. 節慶日曆(靜態台灣電商節日)
2. 季節情境(春/夏/秋/冬消費主題)
3. 電商產業新聞Gemini Grounding
4. Google Trends 台灣熱搜
5. Dcard 熱門討論
6. YouTube 爆紅商品
7. 台灣天氣
8. 台幣匯率
**Fail-safe 設計**:每個 API 用 `_safe()` wrapper失敗時填「本次擷取失敗或無資料不阻塞報告生成。
**輸出 7 頁**:封面三句話 / 節慶+季節(雙卡)/ 新聞+熱搜(雙卡)/ Dcard+YouTube雙卡/ 天氣+匯率(雙卡)/ AI 整合洞察 / 附錄。
### C. AI Prompt 角色化(延續 v3 設計)
| 報表 | AI 角色 | max_tokens |
|---|---|---|
| new_product | PM 商品經理 + 採購主管 | 1800 |
| market_intel | 行銷情報分析師 + BU 主管 | 2000 |
兩種都引用 `MARKET_TREND_2026` 共用知識基底。
## Consequences
### Positive
1. **PM 戰術閉環**new_product 給出「誰值得加碼/觀察/下架」的具體 SMART 行動
2. **CEO/BU 主管的市場視野**market_intel_weekly 把零散的外部資料變成可決策的單一檔案
3. **資料層 0 擴充**:兩種報表都基於現有資料,無需新建 schema
4. **Fail-safe 整合**market_intel 容錯設計,單一 API 失敗不影響整份報告
### Negative
1. **new_product 對小品類失準**CTE 對僅有 < 5 個 SKU 的小品類可能誤判30 天前才開的小品類所有商品都「新進榜」)
2. **market_intel 依賴 Gemini 配額**電商新聞、Trends 等需要 Gemini Grounding配額耗盡時整段填 placeholder
3. **資料新鮮度受限**mcp_collector 是 on-demand 抓,每次生成報告都會 hit 外部 API無快取
### 風險與緩解
- **CTE 跨年判斷**CURRENT_DATE - INTERVAL '90 days' 在閏年 2/29 會略微偏移,但 momo 業務不需要日級精準度
- **外部 API rate limit**`_safe()` 已防呆,連續失敗時整份報告仍能產出(只是內容稀疏)
- **市場情報資料外流風險**:本報告整合多個外部公開資料,無 PII 風險,可對內公開
## Wave 3 餘項與 Wave 4 待辦(下次接力)
剩餘未做(依資料層):
| 報表 | 障礙 | 預估工程 |
|---|---|---|
| clv 客戶終身價值 | 需 user_idPII 限制) | 需先建會員系統 |
| price_elasticity | 需長期定價歷史 | 中4 小時,可從 competitor_price_history 抽) |
| competitor v4 五力 | 需 SKU 數 / 品牌力外部資料 | 大8-12 小時,需擴充 mcp_collector |
| inventory 庫存健康 | 需 stock 表 | 大(需資料層 schema |
| operations 訂單履約 | 需 fulfillment 表 | 大(需資料層 schema |
| finance P&L | 需 finance 表 | 大(需資料層 schema |
## 累計報表清單v3 戰役至今 18 commits 完成 17 種報表中的 13 種)
**可用 13 種**daily / weekly / monthly / strategy / competitor / promo / vendor / quarterly / half_yearly / annual / ttm / category / customer / forecast_pre_event / promo_compare / new_product / market_intel
**DEPRECATED 2 種**bcg / growth
**待 Wave 4 / 資料層** 4 種clv / price_elasticity / competitor v4 / inventory / operations / finance
## References
- 對應 memory`reference_ppt_system.md`v3.1++ 含 Wave 3、新建 `project_ppt_wave3_intel_20260503.md`
- ADR-022/023/024前期

View File

@@ -0,0 +1,111 @@
# ADR-026: PPT 系統 — 價格彈性報告 + 完整戰役收尾路線圖
- **Status**: Accepted
- **Date**: 2026-05-03
- **Deciders**: 統帥
- **Related**: 補完 Wave 3 的 price_elasticity並收尾整套 v3 PPT 戰役ADR-022~026
- **Affects**: `services/ppt_generator.py``routes/openclaw_bot_routes.py``services/openclaw_bot/menu_keyboards.py`
- **Commit**: `16b169d` (price_elasticity)
## Context
ADR-025 後 Wave 3 餘 1 種可從現有資料層做price_elasticity簡化版。本次完成此項並對整套戰役做最終盤點。
剩餘 4 種完全做不了的依賴前置條件:
1. **clv** — 需 user_id會員系統
2. **competitor v4 五力** — 需外部 SKU 數 / 品牌力資料整合
3. **inventory** — 需 stock 表
4. **operations** — 需 fulfillment 表
5. **finance** — 需 finance 表
## Decision
### A. price_elasticity 簡化版
**核心思路**:用 SKU 級平均售價(總業績/數量)做價位分桶,找出「訂單最多的價位區間」作為**價格甜蜜點**(採購選品的關鍵指標)。
**7 個價位桶**
```
< NT$200 / 200-500 / 500-1K / 1K-2K / 2K-5K / 5K-10K / > 10K
```
**主要洞察維度**
1. 甜蜜點集中度(>50% 過度集中、30-50% 主流明確、<30% 分布健康)
2. 高價帶業績佔比(業界健康 30-50%
3. 「斷層」價位SKU 數明顯偏少 → 補貨機會)
**簡化限制聲明**
真正的 price_elasticity 需要「同 SKU 在不同時間的不同售價」做時間序列分析。本版本是「橫斷面分析」snapshot告訴採購「該品類目前消費者最常買的價位帶是哪個」。已在 commit message 與 ADR 註明。
### B. 整套 v3 PPT 戰役完整成果
**18 個 commits38967ce → 16b169d**
| Phase | Commit | 說明 |
|---|---|---|
| v3 重做 | 38967ce..993bdda | 6 種既有報表全升 v3.x暖紙風 + matplotlib + 模板版本快取 + 共用 2026 市場知識基底)|
| Wave 1 | b6fdb4f..5461c92 | 廠商 + 期間回顧 ×4 + 品類深度 + 客戶分析 |
| Wave 2 | 9f04dc3..af6157f | 檔期前瞻 + 多活動比較 + bcg/growth 廢除 |
| Wave 3 | 95a74c3..16b169d | 新品追蹤 + 市場情報週報 + 價格彈性 |
**累計 16 種有效報表 + 2 種 DEPRECATED**
| 角色 | 報表 |
|---|---|
| 戰情/早會 | daily / weekly |
| BU 主管 | monthly / quarterly / half_yearly / forecast / strategy |
| CEO/GM/CFO | annual / ttm / market_intel |
| 採購主管 | vendor / category / new_product / price_elasticity |
| PM 商品經理 | category / new_product / price_elasticity |
| 行銷主管 | promo / promo_compare / customer / market_intel |
| 競品分析 | competitor |
**DEPRECATED**bcg與 strategy 重疊)/ growth已被 quarterly 取代)
### C. 待 Wave 4資料層 / 外部整合擴充後)
| 報表 | 阻塞於 | 解法路徑 | 預估工程 |
|---|---|---|---|
| clv 客戶終身價值 | 無 user_id | 建會員系統 PII 表 | 大(需 PM 階段性需求) |
| competitor v4 五力 | 外部 SKU/品牌力資料 | 擴 mcp_collector 抓 PChome/蝦皮 SKU API + Dcard 品牌討論度 | 大8-12h |
| inventory 庫存健康 | stock 表 | DB schema + ETL pipeline | 大(需採購系統介接) |
| operations 訂單履約 | fulfillment 表 | DB schema + 物流資料 | 大(需物流系統介接) |
| finance P&L | finance 表 | DB schema + ERP 整合 | 大(需財務系統介接) |
## Consequences
### Positive
1. **零售/電商 BI 報表體系完整覆蓋**16 種報表覆蓋採購/PM/行銷/CEO/CFO/戰術/戰情七大角色
2. **資料層復用最大化**:所有 16 種報表都基於同一張 `realtime_sales_monthly`(無需新建 schema
3. **AI 顧問深度跨報表一致**`MARKET_TREND_2026` 共用知識基底 + 角色化 prompt每種報表配對應 AI 角色)
4. **模板版本快取機制**:未來任何報表升版只需 bump `TEMPLATE_VERSIONS`,舊快取自動 miss
5. **共用 generator 模式**period_review 一份解 4 種報表,未來新增報表類型可繼承
### Negative
1. **Telegram 主選單擁擠**:報表選單從原本 7 顆按鈕擴充到 18 顆,視覺密度高
2. **AI prompt token 成本上升**:高顧問深度 promptmax_tokens 1500-2600每生成一份報告 NIM 配額消耗增加
3. **外部 API 依賴**market_intel 依賴 Gemini Grounding配額耗盡時整段 fallback
### 風險與緩解
- **報表選單過載**:未來考慮分層子選單(時間維度 / 角色 / 主題)
- **token 成本**:模板版本快取已實作,同參數秒回不重複呼叫 AI
- **外部 API rate limit**`_safe()` wrapper + fallback 防呆已實作market_intel
## 結論
本戰役歷時 2 天2026-05-02 ~ 2026-05-03共 18 commits從原本 6 種 PPT 報表擴展到 16 種,並完成完整的:
- 視覺全面重做v3 暖紙風)
- AI prompt 顧問深度升級(含 SMART 框架、市場趨勢、角色化)
- 共用資料層 + matplotlib 圖表 + cache versioning + 中英分軌字型 + 部署排程
剩餘 5 種報表clv / competitor v4 / inventory / operations / finance受資料層或外部依賴限制列入 Wave 4 待辦,待相應前置條件具備後接力。
## References
- ADR-022 PPT v3 redesign戰役起點
- ADR-023 Wave 1 擴展(廠商/期間/品類/客戶)
- ADR-024 Wave 2檔期前瞻/多活動比較/廢除)
- ADR-025 Wave 3新品/市場情報)
- ADR-026 Wave 3 收尾(價格彈性/完整路線圖)
- 對應 memory`reference_ppt_system.md` / 戰役紀錄:`project_ppt_v3_campaign_20260502.md``project_ppt_wave1_expansion_20260503.md``project_ppt_wave3_intel_20260503.md`

View File

@@ -0,0 +1,114 @@
# ADR-027Primary Ollama 遷移至 GCP 高效能主機
- **Status**: Accepted
- **Date**: 2026-05-03
- **Decision Maker**: 統帥
- **Author**: Antigravity
## Context
為了提升 AI 處理速度與穩定性,並減輕本地 188 主機的負載,現已啟用一台位於 GCP 的高效能主機作為 Primary Ollama 伺服器。
原本地 188 或 111 的 Ollama 轉為 Fallback 節點。
## Decision
**1. 高效能主機配置**
- **Public IP**: `34.21.145.224`
- **服務端口**: `11434`
- **主要模型**:
- `qwen2.5-coder:7b` (程式碼修復與開發)
- `hermes3:latest` (Llama 3 級別,用於 Hermes 邏輯)
- `bge-m3:latest` (Embedding 專用)
**2. 環境變數對應**
- `OLLAMA_HOST_PRIMARY`: `http://34.21.145.224:11434`
- `OLLAMA_HOST_FALLBACK`: `http://192.168.0.111:11434` (或 188 本地節點)
**3. 資源分工**
- **Primary (GCP)**: 承載 90% 以上的 LLM 推理與 Embedding 請求。
- **Fallback (Local)**: 當 GCP 連線超時或故障時,自動切換至本地節點( Hermes Rule-based 或本地 Ollama
## Alternatives Considered
- **維持全本地**: 188 主機 Load 較高,且 GPU 資源競爭激烈。
- **全雲端 API (OpenAI/Gemini)**: 成本較高,且無法控制模型版本與延遲。
## Consequences
- **優點**: 推理速度提升,系統負載均衡,具備異地備援能力。
- **缺點**: 依賴外部網路連線,需注意 GCP 出口流量成本與安全性(目前採 IP Allowlist 保護)。
## Verification
- `curl http://34.21.145.224:11434/api/tags` 驗證模型列表正常返回。
- 測試 `qwen2.5-coder:7b``bge-m3:latest` 回應正常。
---
## 附錄2026-05-03 戰役 v5.0 補述)
> **補述背景**Operation Ollama-First v5.0 戰役 Phase 0/1/2/3 完成後,本附錄校正本 ADR 的主機架構與 fallback 鏈描述並廢止「188 Ollama」概念。完整治理規則改由 ADR-028 / ADR-029 承接。
### 附錄 A三主機架構取代原 GCP / 111 二段描述)
戰役 v5.0 啟用第二台 GCP 高效能主機後,主機級聯升級為三層:
| 角色 | 公網 IP / 主機 | 儲存 | 規格 / 用途 |
|---|---|---|---|
| **Primary** | `34.143.170.20:11434` | SSD | 9× 加載 / 2× 推理v5.0 戰役新主機)|
| **Secondary** | `34.21.145.224:11434` | SSD | 同等效能備援;本 ADR 原 Primary 降為次主 |
| **Fallback** | `192.168.0.111:11434`HDD| HDD | 統帥 Mac 上的 Ollama.app最後一道本地防線 |
**程式契約**:所有 LLM 呼叫必須走 `services/ollama_service.resolve_ollama_host()`Phase 2 A6 落地),按 Primary → Secondary → Fallback 順序探測:
- HTTP probe `GET /api/version`2s timeout取代原純 TCP 探測B3 修補)
- 失敗主機 `mark_unhealthy()` 30sB4TTL 內直接跳下一台
- 寫死 IP 已全面消除(`services/aider_heal_executor.py:48-49``services/code_review_pipeline_service.py:218-225` 兩處 N2/N3 修補)
詳見 `docs/phase2_deploy_verify_20260503.md`
### 附錄 B4 條獨立 fallback 鏈(不存在「線性 LLM 鏈」)
戰役 v5.0 audit 證實系統實際有 4 條(嚴格說 5 條)獨立 fallback 鏈,語意各異不可合併:
1. **Ollama host 級**(基礎設施層)
`gcp_ollama` (Primary) → `ollama_secondary``ollama_111`
實作:`services/ollama_service.resolve_ollama_host()`
2. **Hermes 競價 / 意圖分類**(戰術層)
Ollama → 規則引擎兜底
實作:`services/hermes_analyst_service.py`ADR-004
3. **NemoTron 派遣**(行動層)
NIM `meta/llama-3.1-8b` → Hermes 規則引擎
實作:`services/nemoton_dispatcher_service.py`ADR-004
4. **OpenClaw Q&A**(戰略層 / Telegram
Gemini 2.5 Flash → NIM `deepseek-v3.2` → 字面 fallback
Phase 3 A7 已切Hermes qwen3:14b → 信心低升 Gemini → NIM
實作:`services/openclaw_strategist_service.py` / `routes/openclaw_bot_routes.py:6784-6843`
5. **MCP 即時情報**(外部資訊層)
Gemini Grounding L1 → Gemini Grounding L2 → Ollama L3 → 靜態字串
實作:`services/mcp_collector_service.py:163-214`
### 附錄 C廢止項
- **「188 Ollama」概念全面廢止**
188 主機(`192.168.0.188`)僅作為以下用途:
- SSH AutoHeal target`docker restart` / log scanADR-013
- momo-pro Docker Compose 運行環境ADR-008
- momo-postgres / momo-db / momo-scheduler / momo-telegram-bot 容器宿主
- **不安裝、不運行 Ollama**Ollama 全部走 GCP Primary / Secondary 或統帥 Mac 111
- 任何「188 Ollama」字樣的舊文件視為過時以本附錄為準
-`OLLAMA_HOST_FALLBACK = http://192.168.0.111:11434` env var 仍保留,但解析路徑改由 `resolve_ollama_host()` 統一管控,不再被任何呼叫點寫死引用
### 附錄 D治理規則升級指引
戰役 v5.0 後,所有 LLM 治理決策改以以下文件為準:
- 路由白名單 / caller 清單 / Gemini 鎖定場景 → **ADR-028**
- Hermes 主塔 vs OpenClaw 副塔分工 → **ADR-029**
- 部署驗證劇本 → `docs/phase2_deploy_verify_20260503.md`
- DB 觀測層 schema → `migrations/024_create_ai_calls_table.sql` ~ `026_add_embedding_signature.sql`
- Logger 程式契約 → `services/ai_call_logger.py`
本 ADR-027 保留作為戰役起點的歷史紀錄,不再作為主要參照入口。

View File

@@ -0,0 +1,270 @@
# ADR-028: LLM 路由統一準則 — Ollama-First 五大支柱
- **Status**: Accepted
- **Date**: 2026-05-03
- **Decision Maker**: 統帥
- **Author**: Operation Ollama-First v5.0Codex / A12 planner
- **Supersedes**: 無(補述 ADR-027非取代
- **Related**: ADR-002pgvector 唯一向量庫、ADR-003Hermes embedding 本地化、ADR-004NemoTron 配額耗盡 fallback、ADR-008部署實機驗證、ADR-013AIOps AutoHeal、ADR-018四 Agent 控制面、ADR-027Primary Ollama on GCP
---
## Context
ADR-027 在 2026-05-03 啟用 GCP 高效能主機作為 Primary Ollama但戰役 v5.0 Phase 0 的 onboarder audit`docs/phase0_audit_report_20260503.md`)揭露三項治理斷層:
1. **34 個 LLM 呼叫點分散治理失能**
- audit 完整盤點 `services/``routes/` 共 34 處 LLM 呼叫,分散在 9 個 service / 4 個 route 檔。
- `AIGenerationHistory` 結構化紀錄覆蓋率僅 4/34 = 11.8%,其餘 88% 完全沒結構化遙測。
- 兩處「寫死 111」的呼叫點`services/aider_heal_executor.py:48-49``services/code_review_pipeline_service.py:218-225`)違反 ADR-027 的 Primary/Fallback 原則。
2. **4 條獨立 fallback 鏈缺一致性**
- 不存在「線性 LLM 鏈」假設Ollama 主機級、Hermes 競價、NemoTron 派遣、OpenClaw Q&A、MCP 即時情報各自為政。
- 各鏈 timeout / 探測 / 降級語意不一,故障時行為不可預測。
3. **provider/caller 命名漂移**
- 戰役清單原列 26 個呼叫點audit 補出 8 個遺漏;`openclaw_qa_nim` 此類 fallback 命名靠執行期動態組成(`services/openclaw_strategist_service.py:737`),缺集中字典。
- DB 端在 Phase 1 已加 provider CHECK constraint`migrations/024_create_ai_calls_table.sql:88-91`),但 caller 仍是自由字串critic-A11 於 phase1_final_critic_signoff H5 點名)。
ADR-027 解決了「主機去哪裡」,但未統一「誰能呼叫」「呼叫去哪一台」「為何選這個」。本 ADR 是 ADR-027 的決策補述,把 Phase 0/1/2/3 戰役落地的成果固化為憲法級準則,供未來 Phase 4-12 與所有新 Agent 共同遵循。
---
## Decision — 五大支柱
### 支柱 1三主機級聯Triple-Host Cascade
取代 ADR-027 原本「GCP / 111」二段架構。
| 角色 | 主機 | 儲存 | 用途 |
|---|---|---|---|
| Primary | `34.143.170.20` | SSD | 9× 加載 / 2× 推理v5.0 戰役新主機)|
| Secondary | `34.21.145.224` | SSD | 同等效能備援ADR-027 原 Primary 降為次主 |
| Fallback | `192.168.0.111` | HDD | 最後一道本地防線,統帥 Mac 上的 Ollama.app |
`services/ollama_service.resolve_ollama_host()`Phase 2 A6 落地)按 Primary → Secondary → Fallback 順序探測:
- HTTP probe `GET /api/version`2s timeoutPhase 2 B3 修補)
- 失敗主機標 `mark_unhealthy()` 30sPhase 2 B4TTL 內直接跳下一台
- 任何呼叫點都必須走 `resolve_ollama_host()`,禁止寫死任何 IP
### 支柱 2Ollama 優先Ollama-First
預設所有 LLM 推理都走 Ollama三主機級聯只有支柱 4 列的 7 個鎖定場景才允許走 Gemini。
**判定原則**
- 高頻、低延遲敏感、戰術層 → Ollama
- 低頻、戰略洞察、需 Grounding/長 context、HITL pre-fetch → Gemini
**成本影響**Ollama 三主機都是 self-hosted邊際 token 成本 = 0Gemini 月支出受 7 個鎖定場景上限約束。
### 支柱 3雙塔分工Twin-Tower
詳見 ADR-029。簡述
- **Hermes 主入口L1 戰術塔)**:高頻 Ollama-only所有日常意圖分類、競價分析、KPI 計算、Q&A 第一響應走 Hermes。
- **OpenClaw 副引擎L3 戰略塔)**:低頻鎖定 5 個 Gemini 場景,月/年報、Code Review、EA HITL、Meta 自審等戰略產出。
### 支柱 4Gemini 鎖定 7 個場景
只有以下 7 個 caller 允許呼叫 `gemini` provider其餘任何 caller 走 Gemini 必經 ADR
| # | Caller | 檔案位置 | 用途 | 模型 |
|---|---|---|---|---|
| 1 | `mcp_l1_grounding` | `services/mcp_collector_service.py:32` (LOCKED-GEMINI 註解) | MCP L1 Grounding即時情報| `gemini-2.0-flash` |
| 2 | `mcp_l3_ollama` 兜底前的 L2 | `services/mcp_collector_service.py:33` MCP_FALLBACK_MODEL | MCP L2 Grounding | `gemini-1.5-flash` |
| 3 | `ppt_gemini` | `routes/openclaw_bot_routes.py:98` (LOCKED-GEMINI) + `_call_gemini` 約 line 2464 | PPT 簡報深度分析 | `gemini-2.0-flash` |
| 4 | `openclaw_weekly` / `openclaw_monthly` | `services/openclaw_strategist_service.py:1102` weekly + `:1628` monthly + `:40` STRATEGY_MODEL (LOCKED-GEMINI) | 週/月報敘事(**註**annual 報告尚未實作,目前 OpenClaw 僅 weekly/monthly/daily/meta| `gemini-2.5-flash` |
| 5 | `code_review_openclaw` | `services/code_review_pipeline_service.py:46` REVIEW_MODEL (LOCKED-GEMINI) | Code Review 高階評估 | `gemini-2.5-flash` |
| 6 | `ea_engine` (HITL) | `services/elephant_alpha_orchestrator.py:88` AgentCapability.openclaw model (LOCKED-GEMINI)`hermes_ea_prefetch` 走 Hermes Ollama 不在此鎖定 | EA HITL escalationADR-021| `gemini-2.0-flash` |
| 7 | `openclaw_qa` 升級分支 | `services/openclaw_strategist_service.py:56` `generate_strategy_response` (Phase 3 A7 已加 Ollama-first feature flagflag=true 時 Ollama 失敗才升級 Gemini) | 複雜 SKU 推理Hermes/qwen3 品質低時升級)| `gemini-2.5-flash` |
新增 Gemini caller 必須走 ADR reviewDB CHECK constraint 將於 Phase 5 後補critic-A11 H5
### 支柱 5可觀測性先行Observability-First
所有 LLM 呼叫必須經 `services/ai_call_logger.log_ai_call()` 雙寫 `ai_calls`Phase 1 A4 落地)。
**遙測契約**
- caller / provider / model 必填provider 由 DB CHECK 約束在白名單內)
- input_tokens / output_tokens / duration_ms / status / cost_usd 必填
- request_id 可選但 fallback 鏈必須串接(如 `code_review_hermes``code_review_openclaw``code_review_elephant` 三鏈共用)
- `meta JSONB` 不得超 8192 octet`error TEXT` 不得超 4096 octetmigration 024 H2
- chat_id 等 PII 必經 sha256 截 12 字後存入Phase 2 後補丁critic H6
**自動化護欄**
- `ai_call_budgets` 7 個 provider 月度預算gemini/claude/nim/nim_via_elephant/openrouter/gcp_ollama/ollama_111+ 3 條全供應商總額daily/weekly/monthly= 10 筆種子預算migration 025
- 每日 23:55 token report 推 TelegramA5 落地)
- AIGenerationHistory 覆蓋率必須 ≥ 90%v5.0 戰役 KPIPhase 5 報表追蹤
---
## Provider 白名單DB CHECK 約束)
`migrations/024_create_ai_calls_table.sql:51-58` `chk_ai_calls_provider` 鎖定以下 8 值:
| Provider | 主機 | 計費 | 用途 |
|---|---|---|---|
| `gcp_ollama` | Primary `34.143.170.20:11434` | 0self-hosted| 戰役 v5.0 主主機 |
| `ollama_secondary` | Secondary `34.21.145.224:11434` | 0 | 同等效能備援架構保留logger 端 url-based 推斷待 Phase 7+ |
| `ollama_111` | Fallback `192.168.0.111:11434` | 0 | 最後一道防線 |
| `gemini` | Google AI API | metered | 鎖定支柱 4 的 7 個場景 |
| `claude` | Anthropic API | metered | Phase 7 Frontier 升級保留Code Review L0 (Opus 4.7) + EA HITL (Sonnet 4.6)budgets 種子 $10/月已預設 |
| `nim` | NVIDIA NIM `https://integrate.api.nvidia.com/v1` | 80 calls/day 配額 | NemoTron 派遣ADR-004+ Code Review fallback |
| `nim_via_elephant` | NIM via `services/elephant_service.py` | 同 NIM 配額 | Code Review ElephantAlpha 49B 鏈 |
| `openrouter` | OpenRouter保留 | metered | PPT deepseek-v3.2 鏈 + 預留 Phase 9 多供應商實驗 |
> **三層一致性備忘**critic-A11 B4 修補DB CHECK = 8 個ADR-028 = 8 個,`services/token_report_service.py` `_PROVIDER_DISPLAY` 後續需補 `ollama_secondary`H5 待修,列為 Phase 7 整合任務)。
---
## Caller 白名單(程式碼集中字典)
戰役 v5.0 Phase 1 A4 logger 接入後,固定字串集中於 `services/ai_call_logger.py` 與各 caller。常見 13 + 5 NIM 變體:
```
hermes_intent / hermes_analyst / hermes_rule_engine
code_review_hermes / code_review_openclaw / code_review_elephant
openclaw_qa / openclaw_qa_nim
openclaw_weekly / openclaw_weekly_nim
openclaw_daily / openclaw_daily_nim
openclaw_monthly / openclaw_monthly_nim
openclaw_meta / openclaw_meta_nim
nemotron_dispatch
openclaw_bot_main / openclaw_bot_gemini / openclaw_bot_nim
embedding_worker / embedding_realtime
mcp_collector_l1 / mcp_collector_l2 / mcp_collector_l3
ppt_generator / ppt_generator_ollama / ppt_generator_nim
ea_hitl_prefetch / ea_autonomous_engine
aider_heal
sales_copy / trend_match / trend_search / product_insights / trend_keywords
telegram_copy / bot_api_copy / trend_crawler / ai_provider_generic
```
新增 caller 必須:
1. 加進 `services/ai_call_logger.py` `_KNOWN_CALLERS` 字典
2. 更新本 ADR 表格
3. 通過 critic 審查
4. Phase 5 後 DB CHECK constraint 將以格式約束(`^[a-z][a-z0-9_]{2,63}$`NOT VALID 補上critic-A11 H5 建議)
---
## 鎖定 Gemini 7 個場景(與支柱 4 對應,含理由)
| 場景 | 為何不能走 Ollama |
|---|---|
| MCP L1/L2 Grounding | Gemini Grounding 是即時 web search 唯一供應商Ollama 無此能力Tavily/Exa 走 Phase 10 不同路徑)|
| PPT 圖檢查 / 簡報分析 | Gemini 多模態 vision 能力遠超 Ollama 本地模型 |
| 週/月/年報敘事 | 商業敘事品質要求高Gemini 2.5 Flash vs qwen3:14b 估差 10-20%phase0_research_report Section 1|
| Code Review 高階評估 | OpenClaw 級審查需 Gemini 2.5 Flash 的程式理解力,本地模型不足 |
| EA HITL pre-fetch | escalation 路徑 5s timeout 內必須拿到結構化 + 高品質回應ADR-021 已定 |
| 複雜 SKU 推理 | Hermes/qwen3:14b 信心 < threshold 時才升級 Gemini繁中商業情境短板TMMLU+ 論文)|
---
## Alternatives Considered
| 方案 | 不採用原因 |
|---|---|
| **A. 單一供應商(全 Gemini 或全 NIM** | 配額硬限NIM 80 calls/day+ 月成本不可控;雲端 API 出口流量風險;違反 FinOps 視角 |
| **B. 全本地(不留 Gemini** | MCP Grounding / vision / 戰略敘事品質本地模型補不齊繁中短板無解phase0_research Section 1.4|
| **C. 多供應商完全互通(任意 caller 任意 provider** | 命名漂移無法治理caller-provider 對應靠程式碼隱式約定,無 DB 護欄token 報表 GROUP BY 失準 |
| **D. 線性 LLM 鏈(一條 fallback 鏈打天下)** | audit 已證明系統有 4 條獨立鏈Ollama host / Hermes / NemoTron / OpenClaw Q&A / MCP語意各異不可合併 |
| **E. 引入 LangChain / LiteLLM 統一抽象層** | 黑盒、難審計、增加依賴;既有 `ai_call_logger` + `resolve_ollama_host` 已具備統一語意,無需第三方 |
---
## Consequences
### 正面
1. **成本可控**Gemini 鎖定 7 場景,月支出有上限;其餘 ~27 個 caller 全走 Ollama 邊際成本 = 0。
2. **遙測 100%**A4 logger 接入後,`ai_calls` 覆蓋率從 11.8% 拉升至接近 100%token / 成本 / 延遲 / 失敗率每日 23:55 自動入袋。
3. **fallback 行為可預測**:三主機級聯 + mark_unhealthy + HTTP probe 取代純 TCP 探測process 卡死也能 5s 內切換。
4. **provider 命名治理**DB CHECK constraint 鎖死 8 個 providercaller 字典集中於程式碼,新增需 ADR。
5. **未來 Phase 4-12 有依據**:所有新 Agent / 新 caller 直接套用本 ADR 的五大支柱與白名單。
### 負面
1. **新 caller 引入有 ADR 摩擦**:每個新 LLM 呼叫點都要 update 本 ADR但這是治理代價而非缺點。
2. **DB CHECK 變更需 migration**provider 白名單擴增(如 Phase 9 加 `claude`)需新 migration + 滾動部署。
3. **Logger 額外延遲**:每個 LLM 呼叫多一層 fire-and-forget 寫入(測試顯示 < 5ms但獨立 thread + dedicated session pool 可控。
### 風險與緩解
| 風險 | 機率 | 緩解 |
|---|---|---|
| Logger 失敗連鎖讓主流程崩 | 低 | `ai_call_logger` kill-switch 連續 10 次失敗自動關Phase 1 已測試 52/52 pass|
| caller typo 污染 token 報表 | 中 | Phase 5 後加格式 CHECK constraintreview 時 grep 比對白名單 |
| Gemini 配額耗盡7 場景同時爆)| 低 | NIM `nvidia/llama-3.3-nemotron-super-49b-v1.5` 鏈 fallbackADR-004 已定 |
| Primary 主機長期掛 | 低 | mark_unhealthy 30s + 三層級聯;最壞情況走 111 本地 |
---
## Verification如何驗證已落地
### V1DB 層
```sql
-- provider CHECK 鎖定
SELECT pg_get_constraintdef(oid) FROM pg_constraint
WHERE conname = 'chk_ai_calls_provider';
-- 期望CHECK (provider IN ('gcp_ollama','ollama_secondary','ollama_111','gemini','nim','nim_via_elephant','openrouter'))
-- 預算種子 10 筆
SELECT period, provider, budget_usd FROM ai_call_budgets ORDER BY period, provider NULLS FIRST;
-- 24h caller 分布(戰役 v5.0 上線後應 ≥ 13 個 distinct caller
SELECT caller, COUNT(*) FROM ai_calls
WHERE called_at >= NOW() - INTERVAL '24h'
GROUP BY caller ORDER BY 2 DESC;
```
### V2程式碼層
```bash
# 不應有寫死 IP
grep -rn "192.168.0.111" services/ routes/ | grep -v "OLLAMA_HOST_FALLBACK\|resolve_ollama_host\|test_"
grep -rn "34.143.170.20\|34.21.145.224" services/ routes/ | grep -v "OLLAMA_HOST_PRIMARY\|test_"
# 所有 LLM 呼叫應走 logger
grep -rn "ollama_service.generate\|google.generativeai\|openai.ChatCompletion" services/ routes/
# 每個 hit 上方應有 with log_ai_call(...) 或 @log_ai_call_decorator
```
### V3每日 token report每日 23:55 入 Telegram
- Section 1 `ollama_pct` ≥ 80%(戰役 KPI
- Section 5 「今日 Ollama Tokens vs 7 日均」應穩定,不應突然降為 0M7 的 openclaw_bot_main 修復後)
- ai_insights `insight_type='daily_token_report'` 每日 1 筆
---
## Migration Plan
| Phase | 項目 | 狀態 | 文件 |
|---|---|---|---|
| 0 | LLM/MCP audit + 替代查證 | ✅ 完成 | `docs/phase0_audit_report_20260503.md` / `docs/phase0_research_report_20260503.md` |
| 1 | DB schema024/025/026+ ai_call_logger + token report | ✅ 完成52/52 tests pass| `docs/phase1_db_design_20260503.md` / `docs/phase1_critic_review_20260503.md` / `docs/phase1_final_critic_signoff_20260503.md` |
| 2 | resolve_ollama_host + HTTP probe + mark_unhealthy + AiderHeal/CodeReview lazy | ✅ 完成13 + 43 tests pass| `docs/phase2_deploy_verify_20260503.md` |
| 3 | OpenClaw Q&A 切 qwen3:14bfeature flag| ✅ 完成A7| 待 Phase 4 黃金集 A/B |
| 4 | 黃金集 A/B 評測 + Hermes daily 摘要遷移A8| 規劃中 | — |
| 5 | Phase 5 報表上線 + caller CHECK NOT VALID | 規劃中 | — |
| 6 | 文件對齊(本 ADR + ADR-029 + ADR-027 附錄)| ✅ 完成 | 本檔 |
| 7-8 | OpenClaw 程式瘦身A10| 規劃中 | — |
| 9 | 預算守門 hard-stop + 多供應商實驗 | 規劃中 | — |
| 10 | MCP 5 顆 🟢 引入postgres / omnisearch / filesystem / firecrawl / git| 規劃中 | — |
| 11 | RAG 一致性護欄embedding_signature 回填 + bge-m3 digest 鎖定)| 規劃中 | — |
| 12 | ai_usage_tracking deprecate + caller 集中 ADR refresh | 規劃中 | — |
---
## References
- ADR-027 Primary Ollama on GCP戰役起點
- ADR-029 Hermes-First 雙塔分工(本 ADR 支柱 3 展開)
- ADR-004 NemoTron 配額耗盡 fallback白名單 NIM provider 來源)
- ADR-013 AIOps AutoHealaider_heal_executor 修補上下文)
- ADR-018 四 Agent 控制面Hermes/NemoTron/OpenClaw/ElephantAlpha 角色定義)
- ADR-021 EA HITL pre-fetchGemini 場景 6 來源)
- `docs/phase0_audit_report_20260503.md`34 呼叫點完整盤點)
- `docs/phase0_research_report_20260503.md`Qwen / DeepSeek-R1 / Search API 三項紅綠燈)
- `docs/phase1_db_design_20260503.md`DB schema 設計理由)
- `docs/phase1_final_critic_signoff_20260503.md`H5/H6 caller / chat_id 護欄缺口)
- `docs/phase2_deploy_verify_20260503.md`resolve_ollama_host / mark_unhealthy 落地驗證)
- 相關 memory`reference_111_mac_ollama.md``reference_env_map.md``feedback_docs_vs_reality.md`

View File

@@ -0,0 +1,223 @@
# ADR-029: Hermes-First 雙塔分工
- **Status**: Accepted
- **Date**: 2026-05-03
- **Decision Maker**: 統帥
- **Author**: Operation Ollama-First v5.0Codex / A12 planner
- **Related**: ADR-001三 Agent 自主學習分工、ADR-002pgvector、ADR-018四 Agent 控制面、ADR-019Telegram Agentic Layer、ADR-027Primary Ollama on GCP、ADR-028LLM 路由統一準則)
---
## Context
ADR-001 / ADR-018 把 Hermes 定位為「L1 Observer / Embedding」、OpenClaw 定位為「L3 Strategist」但實作上的權重失衡與成本失衡讓「分工」變成「OpenClaw 全包」。
### 失衡證據(戰役 v5.0 Phase 0 audit
1. **程式碼體積失衡**
- `services/openclaw_strategist_service.py`**2677 行**HEAD 起 1831 行 + Phase 3/4 增量 846 行)
- `services/hermes_analyst_service.py`**607 行**
- 比率 **4.4×**,但 Hermes 的呼叫頻率高 OpenClaw **約 100 倍**
2. **成本失衡**
- OpenClaw 月燒 Gemini ≈ **50M tokens**(估算依 phase0 audit caller 流量推算)
- Hermes 月燒 Ollama ≈ **30M tokens**,邊際成本 **$0**
- 換句話說Hermes 跑了 60% 流量 = $0OpenClaw 跑了 40% 流量 = 全部 Gemini 帳單
3. **使用者主入口 = Telegram但 Telegram NL 走 OpenClaw**
- 統帥每日數十次答題從 Telegram 走 `routes/openclaw_bot_routes.py:6784-6843` 三層 fallbackOllama → Gemini → NIM
- audit ID #29/30/31 顯示 OpenClaw Bot Q&A 是 Gemini 月支出第二大來源
- ADR-019 的 Agent-First Conversation Layer 把所有用戶輸入導向 `openclaw_decide()`,更放大 OpenClaw 流量
4. **戰略 / 戰術層職責混雜**
- 「每日營運摘要」是高頻戰術(每日 09:00卻走 OpenClaw Gemini → 成本最高頻率最高
- 「KPI 計算」是規則引擎可解的純運算,卻丟給 LLM 寫敘事
- 「Q&A」涵蓋從「上週業績多少」戰術到「下季品類布局建議」戰略全部走同條鏈
5. **Phase 3 A7 已局部驗證**
- 戰役 v5.0 Phase 3 已把 OpenClaw Q&A 第一響應切到 `qwen3:14b`feature flag保留 Gemini 作 fallback
- 該變更顯示「Hermes-tier 模型接戰術 Q&A」是技術可行的
ADR-018 已定四 Agent 角色,但未量化「誰處理高頻流量、誰處理低頻戰略」;本 ADR 是 ADR-018 的成本驅動補述,把 Hermes 從「Observer」升格為「主入口」OpenClaw 縮回「鎖定戰略場景的副引擎」。
---
## Decision — 雙塔分工Twin-Tower
### Hermes 主塔L1 戰術 / 高頻 / Ollama-only
- **定位**:所有 Telegram NL / 競價偵測 / 日常摘要 / KPI 計算 / 第一響應 Q&A 的單一入口
- **資源**:三主機 Ollama 級聯ADR-028 支柱 1邊際成本 0
- **模型**`hermes3:latest`(意圖分類 / 競價)+ `qwen3:14b`Q&A 第一響應Phase 3 已切)
- **降級**Ollama 失敗 → 規則引擎兜底ADR-004 已定)→ 模板化回應,不直接升 Gemini
- **不可越界**:不寫戰略長文(≤ 200 字)、不做 Web Grounding、不做 vision
### OpenClaw 副塔L3 戰略 / 低頻 / 鎖定 5 個 Gemini 場景)
- **定位**:產生月/年報敘事、PPT 顧問深度分析、Code Review 高階評估、EA HITL pre-fetch、複雜 SKU 推理
- **資源**Gemini 2.5 Flash 主NIM `llama-3.3-nemotron-super-49b-v1.5` fallbackADR-004
- **觸發頻率**:日報 1×/日 / 週報 1×/週 / 月報 1×/月 / Code Review 部署觸發 / EA HITL escalation 觸發
- **不可越界**:不接 Telegram 第一響應(一律先過 Hermes信心 < threshold 才升級)
### 升級條件Hermes → OpenClaw
由 Hermes 主塔判定是否需要升級:
1. **意圖分類為「戰略性問題」**如「明年品類規劃」「Q3 競品深度分析」)
2. **複雜 SKU 推理且信心分數 < 0.65**Hermes self-assessment
3. **使用者明確要求「深度報告」**Telegram menu 點 `cmd:strategy` / `cmd:annual` / `cmd:competitor`
4. **EA escalation 事件**ADR-021 已定)
升級時 OpenClaw 必須拿到 Hermes 已有的 context意圖 / 信心 / 既有摘要),不重複呼叫 Ollama。
---
## 職責重劃表(戰前 vs 戰後)
| # | 任務 | 戰前 | 戰後 | 對應戰役 task |
|---|---|---|---|---|
| 1 | 競價威脅偵測(每 4h| Hermes Ollama | Hermes Ollama ✅ 維持 | — |
| 2 | 意圖分類Telegram NL| Hermes Ollama | Hermes Ollama ✅ 維持 | — |
| 3 | 每日營運摘要 | OpenClaw Gemini每日 1×| **Hermes 模板 + Gemini 200 字洞察** | **A8** |
| 4 | KPI 計算(業績 / 庫存 / 達成率)| OpenClaw Gemini | **Hermes 規則引擎**(純運算)| **A8** |
| 5 | Q&A 第一響應Telegram| OpenClaw Gemini → NIM → 字面 fallback | **Hermes qwen3:14b → 信心低升 Gemini** | **A7已落地** |
| 6 | 複雜 SKU 推理 | OpenClaw Gemini | Hermes 信心 < 0.65 → OpenClaw Gemini | A7 條件分支 |
| 7 | PPT 簡報深度分析 | OpenClaw Gemini | OpenClaw Gemini ✅ 鎖定 | — |
| 8 | 週/月/年報敘事 | OpenClaw Gemini | OpenClaw Gemini ✅ 鎖定 | — |
| 9 | Code Review 高階評估 | OpenClaw Gemini | OpenClaw Gemini ✅ 鎖定 | — |
| 10 | EA HITL pre-fetch | Hermes OllamaADR-021| Hermes Ollama ✅ 維持escalation 走 OpenClaw Gemini | — |
| 11 | Meta 自審 | OpenClaw 每 6h | **OpenClaw 每 24h**(降頻 4×| **A10** |
| 12 | 規則引擎兜底 | HermesADR-004| Hermes ✅ 維持 | — |
**淨效果**critic-A11 B5 修補:算術重核):
- 任務 3/4/5 從 OpenClaw Gemini 遷移至 Hermes Ollama → 月省 ~9.5M Gemini tokensA7+A8 試算)
- 任務 11 降頻Meta 自審 6h → 12:00→ 月省 ~2.25M Gemini tokensA10 實測超預估)
- 合計月省 ~11.75M tokens50M → 38.25M = **-23.5%**
- Hermes 流量從 ~30M tokens/月 → 預估 ~120M tokens/月(**+400%,成本不變**
---
## A7 / A8 / A10 落地對照
| Task | 範圍 | 狀態 | 對應檔案 |
|---|---|---|---|
| **A7** | OpenClaw Q&A → qwen3:14bfeature flag| ✅ Phase 3 完成,待 Phase 4 黃金集 A/B 驗證 | `services/openclaw_strategist_service.py` Q&A 入口 |
| **A8** | Hermes daily 摘要 + KPI 規則引擎 | 規劃中Phase 4| `services/hermes_analyst_service.py` 新增 daily_summary / kpi_compute 方法 |
| **A10** | OpenClaw Meta 自審降頻 + 程式瘦身 -29% | 規劃中Phase 7-8| `services/openclaw_strategist_service.py` 拆出戰術層遷移至 Hermes |
---
## 預期效益(量化)
| 指標 | 戰前 | 戰後 | 變化 |
|---|---|---|---|
| Gemini 月支出tokens | ~50M | ~38.25M | **-23.5%** |
| OpenClaw 程式碼行數 | 2677HEAD 1831 + Phase 3/4 增量)| Phase 4 +18 行A10 保守抽出)| Phase 4 行數目標未達;主戰果 = Meta 降頻 |
| Hermes 流量tokens | ~30M | ~120M | **+400%$0** |
| Telegram NL 第一響應延遲 p50 | ~2.5sGemini| ~1.2sOllama 本地)| **-52%**(待 ai_calls 實測) |
| 戰術層 fallback 鏈深度 | 3Gemini→NIM→字面| 2Hermes→規則引擎| **-33%** |
| 月成本Gemini API| baseline | -23.5% | 戰役 v5.0 KPI |
> 上述數字為 Phase 0 audit 推算Phase 5 報表上線後以 `ai_calls` 實測值修訂。
---
## Alternatives Considered
| 方案 | 不採用原因 |
|---|---|
| **A. 維持 ADR-018 現狀OpenClaw 全包)** | Gemini 月支出無上限增長Telegram NL 延遲 p50 ≥ 2.5s 體驗差Hermes 程式碼長期被冷凍 |
| **B. OpenClaw 全切 Ollama廢 Gemini** | 月/年報品質下降 10-20%phase0_research Section 1Code Review / PPT vision 補不齊繁中商業敘事短板TMMLU+ 論文)|
| **C. 把 Hermes 升格 L3、廢 OpenClaw** | OpenClaw 已有 KM 沉澱 / Meta 自審 / 戰略架構,砍掉等於拋棄 1.8% → 80% 觀測能力ADR-019ADR-018 四 Agent 控制面被破壞 |
| **D. 引入第五個 Agent 接戰術層** | 增加心智負擔Hermes 已是現成 L1 Observer升格成本最低統帥 FinOps 視角不偏好新增複雜度 |
| **E. 全部走 NIM避開 Gemini 帳單)** | NIM 80 calls/day 配額硬限,月/年報已經會爆NIM 模型品質 < Gemini 2.5 Flash |
---
## Consequences
### 正面
1. **成本下降 23%**:戰役 v5.0 KPI 第一目標達成。
2. **Telegram NL 延遲減半**:本地 Ollama 三主機級聯 vs Gemini API round-trip。
3. **Hermes 體質升級**從「Observer」升「主入口」未來 Phase 11 RAG 攔截可直接接 Hermes 流量。
4. **程式碼瘦身**A10 採保守抽出2 個 helper行數 -25% 目標未達;主戰果為 Meta 降頻(月省 2.25M tokens。深度瘦身延至 Phase 7+。
5. **ADR-019 真正落地**`openclaw_decide()` 第一響應改走 Hermesagent suggestion shortcut 不再 = OpenClaw 全包。
### 負面
1. **A7 切換有黃金集 A/B 風險**qwen3:14b 繁中短板若實測差距 > 30%,需走 Plan BLlama-3-Taiwan-70B 或退回 Gemini 加 prompt cache
2. **A10 重構工程量大**A10 已執行Phase 4採保守抽出避險4 個報告函數結構差異大深度瘦身daily_summary / kpi_compute 遷移至 Hermes需獨立 Phaserefactor-specialist 範圍。
3. **Hermes 變主入口後故障半徑放大**:原本 Hermes 掛 = 規則引擎兜底;現在掛 = 60% Telegram NL 體驗劣化。需強化 mark_unhealthy + 三主機級聯ADR-027 / ADR-028
### 風險與緩解
| 風險 | 機率 | 緩解 |
|---|---|---|
| qwen3:14b 繁中黃金集 A/B 紅燈 | 中 | Phase 4 跑 50 題繁中商業 Q&A 黃金集;< 0.75 BERTScore 自動 fallback Gemini |
| Hermes 故障 = NL 體驗崩 | 低 | 三主機級聯 + mark_unhealthy 30sADR-028 支柱 1規則引擎兜底ADR-004|
| A8 daily 摘要品質 < 戰前 | 中 | Hermes 模板 + Gemini 200 字洞察混合;不是純 Hermes 全自動 |
| OpenClaw 重構引入 regression | 中 | A10 走 refactor-specialist + 完整 regression testfeature flag 灰度 |
### 降級策略
- A7 feature flag off → 退回 OpenClaw Gemini Q&A
- A8 Hermes daily 失敗 → 走原 OpenClaw Gemini daily保留代碼路徑直至 Phase 8 確認穩定)
- 三主機全掛 → 規則引擎兜底 + Telegram 模板化告警
---
## Verification
### V1流量分布
```sql
-- Hermes vs OpenClaw 月流量比
SELECT
CASE
WHEN caller LIKE 'hermes%' THEN 'hermes'
WHEN caller LIKE 'openclaw%' THEN 'openclaw'
ELSE 'other'
END AS tower,
SUM(input_tokens + output_tokens) AS total_tokens,
COUNT(*) AS calls,
SUM(cost_usd) AS cost
FROM ai_calls
WHERE called_at >= NOW() - INTERVAL '30 days'
GROUP BY 1 ORDER BY total_tokens DESC;
-- 期望hermes tokens ≥ 4× openclaw tokensopenclaw cost > hermes costhermes = $0
```
### V2A7 切換驗證
```sql
-- Q&A 第一響應應 ≥ 80% 走 Hermes / qwen3
SELECT model, COUNT(*) AS calls,
ROUND(100.0 * COUNT(*) / SUM(COUNT(*)) OVER (), 1) AS pct
FROM ai_calls
WHERE caller IN ('openclaw_qa', 'hermes_qa', 'openclaw_bot_main')
AND called_at >= NOW() - INTERVAL '7 days'
GROUP BY model ORDER BY calls DESC;
-- 期望qwen3:14b + hermes3 合計 ≥ 80%
```
### V3Gemini 月支出
- 每月 1 日 token report Section 4「by provider 月成本」對比 baseline 月份
- 預期 `gemini` provider 月成本下降 ≥ 20%
### V4A8 / A10 上線
- Phase 4 後 `caller='hermes_daily_summary'` 應每日 1 筆出現於 ai_calls
- Phase 8 後 `services/openclaw_strategist_service.py` 行數 ≤ 1300
---
## References
- ADR-001 三 Agent 自主學習分工戰役起點Hermes/NemoTron/OpenClaw 原始定義)
- ADR-002 pgvector 唯一向量庫Hermes embedding 落點)
- ADR-004 NemoTron fallback chainOpenClaw NIM 鏈來源)
- ADR-018 四 Agent 控制面(本 ADR 細化的 L1/L3 角色)
- ADR-019 Telegram Agentic LayerHermes 主入口落地路徑)
- ADR-021 EA HITL pre-fetchHermes 預跑 5s timeout 設計)
- ADR-027 Primary Ollama on GCPHermes 主塔的硬體依託)
- ADR-028 LLM 路由統一準則(雙塔分工是支柱 3
- `docs/phase0_audit_report_20260503.md`34 caller 流量分布)
- `docs/phase0_research_report_20260503.md` Section 1qwen3:14b vs Gemini 品質評估)
- 相關 memory`project_three_agent_division.md``feedback_agent_action_ladder.md``reference_telegram_endpoints_map.md`

View File

@@ -0,0 +1,215 @@
# ADR-030: Frontier 多供應商策略 — Anthropic + Google + OpenRouter
- **Status**: Accepted
- **Date**: 2026-05-03
- **Decision Maker**: 統帥
- **Author**: Operation Ollama-First v5.0Phase 7 落地後追認)
- **Supersedes**: 無
- **Related**: ADR-028LLM 路由統一準則、ADR-029Hermes-First 雙塔分工、ADR-027Primary Ollama on GCP
---
## Context
戰役 v5.0 Wave 1 完成後commits 4648673~943de84momo-pro 的 LLM 治理已具備:
- 三主機 Ollama 級聯Primary/Secondary/Fallback
- 13 caller 接入 ai_call_logger
- 7 場景鎖定 Gemini不可走 Ollama
- ADR-029 Hermes-First 雙塔分工
**Phase 7 升級Claude Opus 4.7 接 Code Review** 引入了第二家 Frontier 供應商Anthropic戰役需要明確的多供應商治理準則
1. **何時用 Anthropic vs Google** — 兩家都是 Frontier但能力分布不同
2. **Prompt cache 戰術** — Anthropic 5min ephemeral / Google 隱式,省成本邏輯不同
3. **配額 / 帳單 / 失敗鏈** — 多家供應商需獨立 budget 與 fallback 順序
4. **OpenRouter 角色** — 既有 PPT deepseek-v3.2 鏈為何不丟掉?
**單一供應商風險**(戰役 v3.0 起的核心觀察Gemini 月用量 50M tokens若 Google 端配額爆 / 政策變更 / API key 撤銷 → 全系統癱瘓。多供應商提供工程級 fault tolerance。
---
## Decision
### 1. 三家 Frontier 供應商角色定位
| 供應商 | 模型 | 適用場景 | 計費模式 |
|---|---|---|---|
| **Anthropic Claude** | Opus 4.7 / Sonnet 4.6 / Haiku 4.5 | **程式碼推理** + agentic 工具 + 長 context (200K) | metered / **prompt cache 5min ephemeral** |
| **Google Gemini** | 2.5 Flash / 2.5 Pro | **Search Grounding** + 繁中商業文體 + 多模態 | metered |
| **OpenRouter** | DeepSeek V3.2 / 其他 | **PPT 簡報降級** + 實驗性多供應商 | passthrough metered |
### 2. 場景對應決策矩陣(與 ADR-028 鎖定 7 場景對齊)
| ADR-028 場景 | 主供應商 | 備援供應商 | 依據 |
|---|---|---|---|
| #1 MCP 即時情報 | Gemini 2.5 Pro Grounding | Gemini 1.5 Flash Grounding | 唯一聯網 groundingPhase 10 將補 mcp-omnisearch |
| #2/3/4 OpenClaw 週/月/年報 | Gemini 2.5 Flash | NIM llama-3.3-70b | 長 context + 繁中商業文體 |
| #5 Code Review ⭐ | **Claude Opus 4.7** | Gemini 2.5 Flash → ElephantAlpha 49B | Arena code Elo 1548程式碼 #1+ 200K context |
| #6 EA HITL | Gemini 2.0 Flash | Hermes Ollama 預跑 | 統帥決策時效 |
| #7 PPT 簡報 | Gemini 2.0 Flash | Ollama qwen2.5-coder:7b → DeepSeek V3.2 | 5K rows 長 context |
**#5 Code Review 是 Phase 7 主要升級點**
- **Claude Opus 4.7 程式碼能力 Arena Elo 1548 vs Gemini 2.5 Flash ~1450**+7%
- **200K context** 支援全 repo diffGemini Flash 限 1M 但實測響應品質下降)
- **Prompt cache** 對 Code Review 的「固定 system_prompt + 變動 diff」場景命中率預估 80%+,省 ~90% 成本
- 預估月成本Opus 4.7 $25 vs Gemini 2.5 Flash $5差 $20但 +7% 品質 + 主權冗餘值得)
### 3. Prompt Cache 戰術
#### Anthropic5 分鐘 ephemeral
```python
# services/anthropic_service.py 已實作
kwargs["system"] = [
{"type": "text", "text": system_prompt,
"cache_control": {"type": "ephemeral"}}
]
```
**適用場景**Code Reviewsystem_prompt 固定、diff 變動)、相同 caller 5 分鐘內多次調用。
**省成本估算**
- 第一次調用input_tokens 全價 + cache_creation 收費(同 input
- 第 2-N 次5min 內cache_read 0.1× input 價格 → 省 90%
#### Google Gemini隱式 server-side cache
- 無顯式 API依靠 Google 內部優化
- 不可預測,不納入成本估算
### 4. Budget 與告警(與 migration 025 種子對齊)
| Provider | 月預算 | 種子位置 | 告警閾值 |
|---|---|---|---|
| `claude` | $10 | `ai_call_budgets` | 80% |
| `gemini` | $8 | 同上 | 80% |
| `nim` | $5 | 同上 | 80% |
| `nim_via_elephant` | $5 | 同上 | 80% |
| `openrouter` | $3 | 同上 | 80% |
| `gcp_ollama` | $0.01 | 同上(異常激增告警) | 100% |
| `ollama_111` | $0.01 | 同上 | 100% |
**戰役 v5.0 月成本上限**~$32 USDvs 戰前估算 ~$25 + Phase 7 升級增量 $20 - Hermes-first 攔截 -$13
### 5. Fallback 鏈規範
**Code Review** (Phase 7 落地)
```
L0: Claude Opus 4.7 (CODE_REVIEW_USE_CLAUDE=true)
↓ 失敗 / SDK 不可用
L1: Gemini 2.5 Flash (REVIEW_MODEL)
↓ 失敗
L2: ElephantAlpha NIM 49B (services/elephant_service.py)
```
**EA HITL**(依 ADR-029 雙塔分工):
```
L0: Gemini 2.0 Flash (orchestrator)
↓ 信心度不足
L1: Hermes Ollama 預跑5s timeout免費
↓ 0 threats
L2: short-circuit 不送(避免空泛訊息)⭐ commit 56504ed 修補
```
**新增供應商規則**
- 任何新 Frontier 供應商引入需獨立 ADR如 Phase 7 引入 Claude
- service wrapper 必加 feature flag + `is_available()` 檢查
- 必加 cost budget 種子 + ai_calls.provider 白名單
- 必有對應 unit testfallback 鏈 + cache hit/miss
---
## Alternatives Considered
| 方案 | 否決理由 |
|---|---|
| **A. 單一 Frontier (只用 Gemini)** | 單供應商風險API 撤銷 / 配額爆 / 政策變更全系統癱瘓 |
| **B. 全 Frontier 多家互通all-providers fallback** | 模型輸出格式差異大tool_calls schema、temperature 行為),統一介面工程量 > ROI |
| **C. 自建 Code Review 用 OllamaDeepSeek-V3** | A2 web research 紅燈Ollama deepseek-r1 chat template tools 假支援GitHub Issue #10935 |
| **D. 等 Gemini 3.0 Pro GA 再升級** | Anthropic Claude Opus 4.7 已驗 Arena Elo 1548 程式碼 #1,等待無價值 |
| **E. 用 OpenRouter 統一接入所有家** | 增加中間層延遲 + 失去 Anthropic prompt cache 優勢 |
---
## Consequences
### 正面5
1. **單供應商風險解除**Code Review 從 Gemini 唯一改 Claude L0戰時可一鍵切回 Gemini L1
2. **Code Review 品質 +7%**Arena Elo 1548 vs ~1450
3. **Prompt cache 隱性節省**Code Review 重跑命中率 80%+,省 ~90% Claude 成本
4. **Frontier 配額分散**Claude $10 + Gemini $8 + 其他 = 不會卡單一家配額
5. **未來新增供應商 SOP 化**feature flag + budget + ADR 三件套
### 負面3
1. **月成本 +$20**Claude Opus 4.7 對 Code Review 升級)
2. **依賴 Anthropic SDK**版本升級需追蹤requirements.txt anthropic>=0.40.0
3. **多供應商除錯複雜度↑**:故障時要追三家失敗鏈
### 風險4
1. **Anthropic API key 洩漏**:與 Gemini 同等保護(.env + Gitea Secret
2. **Claude Opus 4.7 模型下架**CLAUDE_MODEL env 可即時切 sonnet-4-6 不需改 code
3. **Cache hit 不如預期**:監控 `ai_calls.cache_read_tokens` 比例,<40% 觸發 INFO 告警
4. **多家帳單分散觀測**token 日報 Section 4「成本拆解」需明確分家統計已就位
---
## Verification
### V1service wrapper 可用性
```python
from services.anthropic_service import anthropic_service
print(anthropic_service.is_available()) # True if ANTHROPIC_API_KEY set
print(anthropic_service.check_connection()) # True if Claude API responds
```
### V2Code Review 切換驗證
```bash
# 戰前CODE_REVIEW_USE_CLAUDE=false
# ai_calls 應只有 provider='gemini' for code_review_openclaw
# 戰後CODE_REVIEW_USE_CLAUDE=true
# ai_calls 應有 provider='claude' + cache_read_tokens > 05min 內第二次)
```
### V3Prompt cache 命中率
```sql
SELECT
AVG(CASE WHEN cache_hit THEN 1.0 ELSE 0.0 END) * 100 AS cache_hit_pct
FROM ai_calls
WHERE provider = 'claude'
AND called_at > NOW() - INTERVAL '7 days';
-- 期望 ≥ 60% (首次 + 5min 內後續)
```
### V4月成本對齊預算
```sql
SELECT provider, SUM(cost_usd) AS month_cost
FROM ai_calls
WHERE called_at > date_trunc('month', NOW())
GROUP BY provider
ORDER BY month_cost DESC;
-- 期望: claude < $10, gemini < $8, total < $32
```
---
## Migration Plan
| Phase | 工作 | 狀態 |
|---|---|---|
| 7.1 | Anthropic SDK 包裝 + COST_TABLE | ✅ commit 943de84 |
| 7.2 | code_review_pipeline 加 L0 Claude 路由 | ✅ commit 943de84 |
| 7.3 | feature flag CODE_REVIEW_USE_CLAUDE 預設 OFF | ✅ commit 943de84 |
| 7.4 | requirements.txt + .env.example | ✅ commit 943de84 |
| 7.5 | 統帥手動:`.env` 加 ANTHROPIC_API_KEY + 翻 ON | ⏳ 待 |
| 7.6 | 觀察 1-2 週 cache hit rate + 成本 | ⏳ 待 |
| 7.7 | 達標後寫 ADR-031同類 SOP 用於其他升級) | ⏳ 後續 |
---
## References
- [Anthropic Prompt Caching](https://docs.anthropic.com/en/docs/prompt-caching)
- [Arena Code LLM Leaderboard](https://arena.ai/leaderboard) — Claude Opus 4.7 Elo 1548
- ADR-028LLM 路由統一準則)
- ADR-029Hermes-First 雙塔分工)
- migration 024/025ai_calls + budgets schema
- services/anthropic_service.pyPhase 7 落地)
- services/code_review_pipeline_service.py:46-58feature flag

View File

@@ -0,0 +1,165 @@
# ADR-031: MCP 自建 Stack — postgres + omnisearch + firecrawl + filesystem
- **Status**: Accepted (待 188 deploy 後 Active)
- **Date**: 2026-05-04
- **Decision Maker**: 統帥
- **Author**: Operation Ollama-First v5.0 / Phase 10
- **Related**: ADR-028LLM 路由統一準則、ADR-032RAG 自主學習、ADR-033三護欄
---
## Context
戰役 v4.0 階段就提案 MCP 自建(取代 Gemini Grounding 唯一聯網能力),但 Phase 10 因 hook 阻擋 SSH 188 deploy先完成本地 docker-compose.mcp.yml + ADR 設計,待統帥手動 `ssh wooo@110 → ssh ollama@188 → docker compose -f docker-compose.mcp.yml up -d` 啟用。
**為何要自建 MCP**
- mcp_collector_service.py 目前 100% 走 Gemini 2.0 Flash Grounding鎖定 7 場景之一)
- 若 Gemini API 配額爆 / 政策變更 → 即時情報唯一通路斷
- 多供應商策略ADR-030需要 Tavily / Exa 作為 grounding 備援
- Claude Code 直連 momo_pro DBread-only RBAC能加速統帥日常 SQL 查詢
---
## Decision — 4 + 3 容器架構
### 4 個 MCP server核心
| Server | port | 用途 | 取代誰 |
|---|---|---|---|
| `postgres-mcp` | 127.0.0.1:3001 | Claude 直連 momo_pro DBread-only | 統帥手動 SQL |
| `mcp-omnisearch` | 127.0.0.1:3003 | Tavily + Exa 統一搜尋 | Gemini Grounding |
| `firecrawl-self` | 127.0.0.1:3002 | 自建爬蟲(含護欄 #2 | 部分自寫 BeautifulSoup |
| `filesystem-mcp` | 127.0.0.1:3004 | 跨主機檔案操作read-only | SSH 跳板手動 cat |
### 3 個輔助容器
| Container | 用途 |
|---|---|
| `firecrawl-redis` | Firecrawl job queue |
| `firecrawl-playwright` | Browser poolmem 1.5g|
| `chrome-reaper` | 每小時清 Chrome 殘留(護欄 #2|
### 護欄 #2 落地Owen v5.0 鐵律)
```yaml
firecrawl-self:
deploy:
resources:
limits:
memory: 2g # ⭐ 硬上限
cpus: '1.5'
environment:
- PLAYWRIGHT_BROWSER_POOL_MAX=3
- SCRAPE_TIMEOUT_MS=30000
healthcheck:
interval: 30s
start_period: 60s
chrome-reaper:
command: 每小時 pkill chrome zombie processes
```
### 安全設計
- **僅 127.0.0.1 暴露**:避免外網直連 DB / 爬蟲服務
- **read-only volume mount**filesystem-mcp 只能讀
- **postgres-mcp RBAC**mcp_readonly role 限 SELECT 到熱表ai_insights / ai_calls / mcp_calls / daily_sales_snapshot / competitor_prices / products
- **Tavily/Exa API key 走 env**:不寫死 docker-compose
### 取代 Gemini Grounding 的 fallback 鏈mcp_collector_service.py 改造)
```
舊:
Gemini 2.0 Grounding → Gemini 1.5 → Ollama → 靜態
新:
mcp-omnisearch (Tavily) → omnisearch (Exa) →
全失敗 → Gemini 2.0 Grounding (保留為 L4)
→ Gemini 1.5 → Ollama → 靜態
```
預期 70%+ 流量走免費 Tavily省 ~70% Gemini Grounding 成本。
---
## Alternatives Considered
| 方案 | 否決理由 |
|---|---|
| **A. 維持 Gemini Grounding 唯一** | 單供應商風險(已是 ADR-030 否決理由)|
| **B. 用 Brave Search API** | 2026-02 取消免費 tierA2 web research 紅燈)|
| **C. 純 Tavily 不要 Firecrawl** | Firecrawl 對 SPA 動態頁更強(蝦皮等 JS-heavy 站)|
| **D. Firecrawl 不限資源** | 188 主機跑 5+ projectOOM 連鎖reference_188_multi_project|
| **E. 用 SaaS Firecrawl Cloud** | 成本(自建免費)+ 資料外流風險 |
---
## Consequences
### 正面5
1. **Gemini Grounding 多供應商**Tavily 主 + Exa 備援,月省 ~70% grounding 成本
2. **Claude 直連 DB**:統帥日常 SQL 查詢可走 MCP 介面read-only 安全)
3. **爬蟲自主性**Firecrawl 取代部分自寫爬蟲SPA 反爬蟲更強
4. **零外部 SaaS 依賴**:全部自建在 188Tavily/Exa 是 API 不是 SaaS
5. **Owen 護欄 #2 落地**mem_limit + chrome-reaper 防 OOM
### 負面3
1. **188 主機資源占用 +4-5GB RAM**Firecrawl 2g + Playwright 1.5g + 其他)
2. **Tavily/Exa API key 維護**:申請 + 月配額追蹤
3. **mcp_collector_service.py 重構工作量**~200 行改動
### 風險3
1. **Firecrawl OOM 連鎖**mem_limit 2g 觸發 OOM kill → mitigate by healthcheck + restart
2. **Tavily 免費額度1000/月)爆**mitigate by Exa 備援 + Gemini Grounding L4
3. **postgres-mcp RBAC 設置失誤**mitigate by mcp_readonly role 預先建立 + only SELECT
---
## Verification
### V1健康檢查
```bash
curl http://localhost:3001/health # postgres-mcp
curl http://localhost:3002/health # firecrawl
curl http://localhost:3003/health # omnisearch
curl http://localhost:3004/health # filesystem
# 全部期待 200 OK
```
### V2Firecrawl 資源
```bash
ssh ollama@192.168.0.188 'docker stats momo-mcp-firecrawl --no-stream'
# 期望 < 1.8GBmem_limit 2GB 90%
```
### V3Tavily 配額
```sql
SELECT COUNT(*) FROM mcp_calls
WHERE server = 'omnisearch' AND tool = 'tavily_search'
AND called_at > date_trunc('month', NOW());
-- 期望 < 1000免費額度上限
```
---
## Migration Plan
| 步驟 | 工作 | 狀態 |
|---|---|---|
| 10.1 | docker-compose.mcp.yml 寫完 | ✅ 本 commit |
| 10.2 | ADR-031 撰寫 | ✅ 本 commit |
| 10.3 | 統帥申請 Tavily + Exa API key | ⏳ 待 |
| 10.4 | momo-db 建 mcp_readonly role + GRANT SELECT | ⏳ 待 |
| 10.5 | 188 deploy: docker compose -f docker-compose.mcp.yml up -d | ⏳ 待 |
| 10.6 | mcp_collector_service.py 改用 mcp-omnisearch取代 Gemini Grounding 主路徑)| ⏳ Phase 10.5 |
| 10.7 | 健康檢查 + Firecrawl mem 監控告警 | ⏳ Phase 10.5 |
---
## References
- `docker-compose.mcp.yml`(本 commit
- ADR-028LLM 路由)/ ADR-030多供應商/ ADR-033護欄
- `services/mcp_collector_service.py`(將改造)
- A2 web research 報告:`docs/phase0_research_report_20260503.md`
- mcp-omnisearch GitHubhttps://github.com/spences10/mcp-omnisearch

View File

@@ -0,0 +1,249 @@
# ADR-032: RAG 自主學習迴圈 — Distiller + PromotionGate + 反饋環
- **Status**: Accepted
- **Date**: 2026-05-03
- **Decision Maker**: 統帥
- **Author**: Operation Ollama-First v5.0Phase 11 落地後追認)
- **Supersedes**: 無
- **Related**: ADR-002pgvector 唯一向量庫、ADR-007持久化雙寫、ADR-028LLM 路由統一準則、ADR-029Hermes-First 雙塔分工、ADR-033RAG 三護欄)
---
## Context
戰役 v5.0 Wave 1 完成後momo-pro 已具備 ai_calls / mcp_calls / ai_call_budgets 觀測層,但仍是「無狀態 LLM 用戶」 — 每次 Hermes/OpenClaw 提問都重新燒 token重複問題沒被攔截。
Phase 0 audit 發現:
- 統帥 Telegram 答題 30%+ 是同一類問題「PChome 補貼」「家電促銷檔期」「SKU 競爭力分析」)
- ai_insights 已累積 14k+ 筆pgvector + bge-m3但**沒有 RAG 攔截層**,全部走 LLM
- 預估30% 流量可被 RAG cache 攔截 = 月省 ~9M Hermes/OpenClaw tokens
**Owen 提出三大風險**v5.0 強化護欄):
1. **學習污染**LLM 幻覺自動進 RAG → 正反饋錯誤循環ADR-033 護欄 #1
2. **資源消耗**:自建 Firecrawl Playwright 池吃 188 主機記憶體ADR-033 護欄 #2
3. **Embedding 一致性**bge-m3 floating tag → RAG 召回率悄悄退化ADR-033 護欄 #3
本 ADR 鎖定 **「LLM 結果 → 蒸餾 → Promotion Gate → ai_insights → RAG」自主學習迴圈** 的設計與護欄。
---
## Decision
### 1. 雙表分離設計
| 表 | 用途 | 保留期 | PII 等級 |
|---|---|---|---|
| `rag_query_log` (migration 027) | 每次 RAG 查詢的 audit log | 90 天 | 中query_text 可能含用戶問題)|
| `learning_episodes` (migration 028) | LLM/MCP 結果蒸餾池 | 永久(蒸餾溯源)| 低distilled_text 已過 PII redact|
| `ai_insights` (既有) | 已驗收的知識庫 | 永久 | 經 PromotionGate 過濾 |
### 2. 自主學習迴圈
```
┌─────────────────────────────────────────────────────────────┐
│ LLM 呼叫Hermes/OpenClaw
│ ↓ │
│ RAG-first 攔截cosine >= 0.85 命中) │
│ ↓ 命中 ↓ miss │
│ return synthesize LLM 跑 │
│ (rag_hit=true) ↓ │
│ Distiller 蒸餾 │
│ ↓ │
│ learning_episodes (pending) │
│ ↓ │
│ PromotionGate 4 階段 │
│ ↓ │
│ ai_insights (approved) │
│ ↓ │
│ 下次 RAG 查得到 │
└─────────────────────────────────────────────────────────────┘
```
### 3. Distiller 規則引擎(純 Hermes零 LLM 成本)
```python
QUALITY_RULES = {
'mcp_result': lambda c: 0.8 if len(c) > 200 and len(keywords(c)) >= 2 else 0.4,
'llm_json_ok': lambda c: 0.9, # 結構化 JSON + status='ok'
'llm_text': lambda c: 0.6 if has_zh_numbers(c) else 0.3,
'thumb_up': lambda _: 1.0, # 用戶 👍 反饋
'thumb_down': lambda _: 0.0, # 負樣本不晉升
}
```
**為何不用 LLM 蒸餾?** 避免循環燒錢Distiller 跑頻率高,用 LLM 等於每次 RAG miss 都燒兩次)。
### 4. PromotionGate 4 階段晉升閘v5.0 護欄 #1
```python
class PromotionGate:
STAGE_1_AUTO_QUALITY = 0.7 # 蒸餾品質分
STAGE_2_HALLUCINATION_RULES = [
'可能/也許/我猜測 + 缺具體數字',
'自相矛盾(同段含 A=X 又 A=Y',
'引用不存在 SKU/品牌(查 DB',
]
STAGE_3_DEDUP_THRESHOLD = 0.95 # cosine 相似度
STAGE_4_HUMAN_REVIEW_WEIGHT = 0.8 # 高權重必經 👍/👎
```
**鐵律**weight ≥ 0.8 的 episode **不能跳 Stage 4**,必須推 Telegram 等 24h 反饋。
| 結果 | promotion_status |
|---|---|
| 4 階段全過 | `approved` → 寫入 ai_insights |
| Stage 1 失敗 | `rejected_quality` |
| Stage 2 失敗 | `rejected_hallucination` |
| Stage 3 失敗 | `rejected_duplicate` |
| Stage 4 推送等待 | `awaiting_review` |
| 24h 無反饋 | `expired`weight 降為 0.5,不晉升但保留)|
| 用戶 👎 | `rejected_human` |
### 5. Telegram 反饋環(強制晉升門檻)
```python
# services/telegram_templates.py
def rag_feedback_keyboard(rag_query_log_id: int) -> dict:
return {'inline_keyboard': [[
{'text': '👍 有用', 'callback_data': f'rag_fb:{id}:5'},
{'text': '👎 沒用', 'callback_data': f'rag_fb:{id}:1'},
]]}
def promotion_review_keyboard(episode_id: int) -> dict:
return {'inline_keyboard': [[
{'text': '✅ 通過晉升', 'callback_data': f'pg_ok:{id}'},
{'text': '❌ 拒絕', 'callback_data': f'pg_no:{id}'},
]]}
```
`routes/openclaw_bot_routes.py` 三組 callback handler 已就位Phase 11 落地)。
### 6. Feature Flag 灰度
```python
RAG_ENABLED = os.getenv('RAG_ENABLED', 'false').lower() == 'true'
RAG_DEFAULT_THRESHOLD = float(os.getenv('RAG_DEFAULT_THRESHOLD', '0.85'))
RAG_DEFAULT_TOP_K = int(os.getenv('RAG_DEFAULT_TOP_K', '5'))
```
**預設 OFF**,戰前部署後行為與 v4.x 完全相同。灰度開啟條件:
1. ANTHROPIC_API_KEY 已設Phase 7 已備)
2. learning_episodes 累積 100+ 筆
3. RAG_ENABLED=true + threshold=0.90(保守起步)
4. 1 週後 feedback_score ≥ 4 比率 > 70% → threshold 降至 0.85
### 7. 失敗安全fire-and-forget 哲學)
| 失敗模式 | 行為 |
|---|---|
| DB 寫入 rag_query_log 失敗 | 主流程不爆logger.warning |
| embedding 失敗 | 不查 DB 直接 fallback LLM |
| signature 不一致 | log warning + 不採該筆 hit |
| Distiller 寫 learning_episodes 失敗 | LLM 結果照樣回 caller |
| PromotionGate Stage 1-3 失敗 | episode 留 learning_episodes不晉升即可無 DB 副作用)|
---
## Alternatives Considered
| 方案 | 否決理由 |
|---|---|
| **A. 直接 ai_insights 寫入(無蒸餾池)** | LLM 幻覺直接污染知識庫,無 PromotionGate 阻擋(核心風險)|
| **B. LLM 蒸餾(用 Gemini 寫 distill prompt** | 循環燒錢:每次 RAG miss → LLM call → 又燒 LLM 蒸餾 = 2× 成本 |
| **C. 純 push 不 pull無反饋按鈕** | 統帥無法糾正幻覺正反饋錯誤循環Owen 強調的痛點)|
| **D. 跳過 dedupStage 3** | ai_insights 將累積大量重複RAG 查詢無謂耗時 |
| **E. 用 ChromaDB / Qdrant 替代 pgvector** | 違反 ADR-002pgvector 唯一)+ 增加運維面 |
---
## Consequences
### 正面5
1. **重複問題攔截**:預估月省 ~9M Hermes/OpenClaw tokensHermes 流量 -30%
2. **自主學習**:每次 LLM 結果都進蒸餾池,知識庫持續成長
3. **錯誤可糾正**:👎 反饋直接降權,避免幻覺循環污染
4. **零 LLM 蒸餾成本**Distiller 純規則引擎
5. **PII 安全**query_text 截 4KB + human_approver SHA1[:8]
### 負面3
1. **複雜度↑**:兩表 + 4 階段閘 + 反饋環,新人理解曲線陡
2. **Stage 4 人工驗收延遲**:高權重 episode 必須等 24h 才能晉升
3. **embedding 寫入路徑暫缺**(已知 limitationStage 3 dedup 待 Phase 12+ 補
### 風險4
1. **Distiller 規則漂移**:規則引擎可能漏判幻覺 → mitigate by Stage 4 人工驗收
2. **Stage 4 人工疲勞**:統帥不可能 24h 看 Telegram → mitigate by `expired` 自動降級
3. **ai_insights 膨脹**:學習迴圈累積快 → mitigate by Stage 3 dedupPhase 12+ 啟用)
4. **PromotionGate worker cron 未掛**(已知):需 Phase 12+ 排程任務
---
## Verification
### V1RAG 攔截率(部署 1 週後)
```sql
SELECT
COUNT(*) FILTER (WHERE saved_call) AS hit_count,
COUNT(*) AS total,
ROUND(100.0 * COUNT(*) FILTER (WHERE saved_call) / COUNT(*), 1) AS hit_pct
FROM rag_query_log
WHERE queried_at > NOW() - INTERVAL '7 days';
-- 期望 hit_pct >= 25%
```
### V2晉升通過率
```sql
SELECT promotion_status, COUNT(*)
FROM learning_episodes
WHERE created_at > NOW() - INTERVAL '7 days'
GROUP BY promotion_status;
-- 期望 approved + awaiting_review 占 >50%rejected_hallucination < 10%
```
### V3反饋分布
```sql
SELECT feedback_score, COUNT(*)
FROM rag_query_log
WHERE feedback_score IS NOT NULL
GROUP BY feedback_score;
-- 期望 score=5 比率 > 60%
```
### V4Embedding 一致性v5.0 護欄 #3
```sql
SELECT embedding_signature, COUNT(*)
FROM ai_insights
WHERE embedding IS NOT NULL
GROUP BY embedding_signature;
-- 期望單一簽名(多個 = 模型版本漂移,需處理)
```
---
## Migration Plan
| Phase | 工作 | 狀態 |
|---|---|---|
| 11.1 | rag_query_log + learning_episodes schema | ✅ migration 027/028 commit 2f20d8d |
| 11.2 | rag_service.py + learning_pipeline.py | ✅ commit c7d6db3 |
| 11.3 | Hermes/OpenClaw RAG-first 整合 | ✅ commit c7d6db3 |
| 11.4 | Telegram 反饋按鈕 + callback | ✅ commit c7d6db3 |
| 11.5 | learning_episodes.embedding 寫入 | ⏳ Phase 12+ |
| 11.6 | PromotionGate worker cron 掛排程 | ⏳ Phase 12+ |
| 11.7 | awaiting_review Telegram 推播 | ⏳ Phase 12+callback 已就位)|
| 11.8 | RAG_ENABLED=true 灰度啟用 | ⏳ 1 週觀察期後 |
---
## References
- `migrations/027_create_rag_query_log.sql`
- `migrations/028_create_learning_episodes.sql`
- `services/rag_service.py`532 行)
- `services/learning_pipeline.py`750 行)
- `tests/test_rag_service.py` + `test_learning_pipeline.py` + `test_promotion_gate.py`70 unit tests
- `docs/phase11_db_design_20260503.md`
- ADR-002pgvector 唯一向量庫)
- ADR-007雙寫保證
- ADR-029Hermes-First 雙塔分工)
- ADR-033RAG 三護欄)— 即將補

View File

@@ -0,0 +1,262 @@
# ADR-033: RAG 治理三護欄 — Promotion Gate / Firecrawl 資源 / BGE-M3 一致性
- **Status**: Accepted
- **Date**: 2026-05-03
- **Decision Maker**: 統帥
- **Author**: Operation Ollama-First v5.0Owen 三點專業洞察 → v5.0 強化)
- **Related**: ADR-032RAG 自主學習迴圈、ADR-031MCP 自建、ADR-002pgvector、ADR-027Primary Ollama on GCP
---
## Context
戰役 v4.0 階段 Owen 提出三點專業洞察,被升級為 v5.0 護欄級鐵律:
1. **學習污染風險**LLM 幻覺自動進 RAG → 正反饋錯誤循環
2. **Firecrawl 資源消耗**:自建 Playwright 池吃 188 主機記憶體
3. **BGE-M3 Embedding 一致性**floating tag → RAG 召回率悄悄退化
這三點**不是普通建議,而是 RAG 系統能否安全長期運轉的命脈**。本 ADR 鎖定三護欄的設計決策與驗收條件。
---
## Decision — 三護欄架構
### 護欄 #1Promotion Gate學習污染防護
**核心原則**反饋按鈕從「選配」升級為「強制晉升門檻」。learning_episodes → ai_insights 必經 4 階段嚴格門檻。
#### 4 階段晉升閘
```
learning_episodes (pending)
↓ Stage 1: quality_score >= 0.7(蒸餾器自動評分)
↓ Stage 2: 無幻覺檢測(規則引擎,零 LLM
↓ Stage 3: 與既有 insight 相似度 < 0.95(去重)
↓ Stage 4: weight >= 0.8 必經 Telegram 👍/👎 人工驗收
ai_insights (approved)
```
#### Stage 2 幻覺檢測規則
```python
HALLUCINATION_PATTERNS = [
# 規則 1含「可能 / 也許 / 我猜測」+ 缺具體數字
lambda txt: any(p in txt for p in ['可能', '也許', '我猜', '推測'])
and not any(c.isdigit() for c in txt),
# 規則 2自相矛盾同段含 'A=X' 又含 'A=Y'
detect_contradiction,
# 規則 3引用不存在 SKU/品牌(查 DB
lambda txt: not _verify_skus_exist(extract_skus(txt)),
]
```
#### Stage 4 強制門檻Owen 鐵律)
- weight >= 0.8 → 推 Telegram + 等 24h 👍/👎
- 24h 無回應 → `expired`weight 降 0.5,不晉升)
- 用戶 👎 → `rejected_human`(永不晉升)
- 用戶 👍 → `approved` 寫 ai_insights
**無條件規則**:高權重 episode 不能跳 Stage 4即使 Stage 1-3 都過。
### 護欄 #2Firecrawl 資源護欄188 主機保護)
#### Docker 限制
```yaml
# docker-compose.mcp.ymlPhase 10 將部署)
services:
firecrawl-self:
image: firecrawl/firecrawl:latest
deploy:
resources:
limits:
memory: 2g # ⭐ Owen 要求硬上限
cpus: '1.5'
environment:
- PLAYWRIGHT_BROWSER_POOL_MAX=3 # 瀏覽器池上限
- SCRAPE_TIMEOUT_MS=30000
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3002/health"]
interval: 30s
```
#### Chrome 殘留清理 sidecar
```yaml
chrome-reaper:
image: alpine:3
command: |
sh -c "while true; do
docker exec firecrawl-self pkill -f 'chrome.*--type=zygote' 2>/dev/null;
docker exec firecrawl-self pkill -f 'chrome.*--type=renderer' 2>/dev/null;
sleep 3600;
done"
```
#### Telegram 告警
- 每小時檢查 firecrawl 容器 RSS
- > 1.8GB → 🟠 P2 告警(記憶體即將達上限)
### 護欄 #3BGE-M3 Embedding 一致性RAG 命脈)
#### 風險來源
- `bge-m3:latest` floating tag → Ollama upgrade 跳版本
- normalize / pooling 參數未顯式傳遞 → server-side 預設改變無感知
- 跨主機GCP / Secondary / 111模型版本可能不一致
#### 簽名鎖定機制
```python
# services/rag_service.py
def get_embedding_signature(
model: str = 'bge-m3:latest',
dim: int = 1024,
normalize: bool = True,
) -> str:
"""SHA1({model}|{normalize}|{dim})[:12]"""
raw = f"{model}|{str(normalize).lower()}|{dim}"
return hashlib.sha1(raw.encode()).hexdigest()[:12]
```
#### Schema 強制migration 026
```sql
ALTER TABLE ai_insights
ADD COLUMN IF NOT EXISTS embedding_signature VARCHAR(64);
CREATE INDEX CONCURRENTLY idx_ai_insights_embedding_signature
ON ai_insights (embedding_signature)
WHERE embedding IS NOT NULL;
```
#### 啟動時驗證Phase 11.0 護欄)
```python
def verify_embedding_consistency():
"""RAG service 啟動時跑:
用同一段測試文字呼叫 GCP / Secondary / 111 三主機,
驗證 cosine 距離 < 1e-4浮點誤差否則拒絕啟動。
"""
test_text = "momo電商競品分析測試向量一致性檢查"
embeddings = {
host: call_ollama(host, 'bge-m3:latest', test_text)
for host in [GCP_PRIMARY, GCP_SECONDARY, OLLAMA_111]
}
diffs = [cosine_distance(embeddings[a], embeddings[b])
for a, b in itertools.combinations(embeddings, 2)]
if max(diffs) > 1e-4:
raise EmbeddingInconsistencyError(...)
```
#### RAG 查詢時保護
```python
# rag_service.py:_select_hits
for hit in candidates:
if hit.embedding_signature != current_signature:
logger.warning(f"Signature mismatch: hit={hit.id}, "
f"expected={current_signature}, got={hit.embedding_signature}")
continue # 不採用該筆
```
---
## Alternatives Considered
| 方案 | 否決理由 |
|---|---|
| **A. RAG 不要反饋按鈕(純自動晉升)** | LLM 幻覺進 RAG 後正反饋錯誤循環,是 RAG 系統最危險的失敗模式 |
| **B. Firecrawl 不限資源(讓它跑)** | 188 主機跑 5+ projectreference_188_multi_projectOOM 會拖垮其他容器 |
| **C. BGE-M3 用 :latest 接受漂移** | 模型升級時無告警RAG 召回率悄悄退化,問題暴露時難回溯 |
| **D. 三護欄都用 LLM 做(如 LLM 蒸餾、LLM 幻覺檢測)** | 循環燒錢 + 引入新幻覺風險LLM 檢測 LLM 幻覺)|
| **E. Stage 4 改為非強制(高 weight 直接 approved** | 違反 Owen 鐵律 — 統帥反饋是 RAG 系統不被污染的最後一道防線 |
---
## Consequences
### 正面5
1. **學習污染防火牆**4 階段閘 + 強制人工驗收,幻覺進 RAG 機率 < 5%
2. **資源預測性**Firecrawl mem_limit 2g + chrome-reaper188 主機絕對安全
3. **模型升級可控**embedding_signature 不變才 RAG 採用,模型漂移立即可見
4. **PII 安全**human_approver SHA1[:8],反饋紀錄不暴露 Telegram username
5. **成本可控**純規則引擎Stage 1-3+ 24h auto-expireStage 4零 LLM 成本
### 負面3
1. **Stage 4 統帥疲勞**:高權重 episode 都要看 Telegram → mitigate by `expired` 自動降級
2. **Firecrawl mem 2g 上限可能太小**:複雜 SPA 爬蟲可能超 → 監控告警 + 可調 env
3. **Embedding signature 變更需全表回填**PG14 ADD COLUMN metadata-only 不鎖表,但回填 14k+ 筆需 worker 跑數小時
### 風險4
1. **Stage 2 規則漏判**:規則引擎可能誤放幻覺進 → mitigate by Stage 4 人工最後關
2. **Firecrawl OOM 連鎖**mem_limit 觸發 OOM kill → mitigate by healthcheck + 重啟策略
3. **Embedding 模型升級時 RAG 完全失效**:所有 hit signature 不符 → 安全降級為「LLM-only」直到回填完成
4. **24h expired 太久**:用戶可能來不及反饋 → 可調 `HUMAN_REVIEW_TIMEOUT_HOURS`
---
## Verification
### V1Promotion Gate 阻擋率(部署 1 週後)
```sql
SELECT promotion_status, COUNT(*)
FROM learning_episodes
WHERE created_at > NOW() - INTERVAL '7 days'
GROUP BY promotion_status;
-- 期望: rejected_hallucination >= 1證明 Stage 2 真的擋下幻覺)
-- 期望: approved + awaiting_review > 50%
```
### V2Stage 4 反饋率
```sql
SELECT
COUNT(*) FILTER (WHERE promotion_status = 'awaiting_review') AS pending,
COUNT(*) FILTER (WHERE promotion_status = 'approved' AND human_approver IS NOT NULL) AS human_approved,
COUNT(*) FILTER (WHERE promotion_status = 'rejected_human') AS human_rejected,
COUNT(*) FILTER (WHERE promotion_status = 'expired') AS expired
FROM learning_episodes;
-- 期望: human_approved + human_rejected > expired統帥真的有看 Telegram
```
### V3Firecrawl 資源(部署後)
```bash
ssh ollama@192.168.0.188 'docker stats firecrawl-self --no-stream --format "{{.MemUsage}}"'
# 期望 < 1.8GBmem_limit 2GB 的 90%
```
### V4Embedding 一致性
```sql
SELECT embedding_signature, COUNT(*), MIN(created_at), MAX(created_at)
FROM ai_insights
WHERE embedding IS NOT NULL
GROUP BY embedding_signature
ORDER BY MAX(created_at) DESC;
-- 期望: 單一簽名(多個 = 模型漂移)
```
---
## Migration Plan
| 護欄 | 部分 | 狀態 |
|---|---|---|
| #1 PromotionGate Schema | learning_episodes 8 狀態機 | ✅ migration 028 commit 2f20d8d |
| #1 PromotionGate Service | 4 階段邏輯 + reject/promote | ✅ services/learning_pipeline.py commit c7d6db3 |
| #1 反饋按鈕 | rag_feedback + promotion_review | ✅ telegram_templates + bot routes commit c7d6db3 |
| #1 awaiting_review 推播 | Telegram 推 episode 給統帥看 | ⏳ Phase 12+ |
| #2 Firecrawl mem_limit | docker-compose.mcp.yml | ⏳ Phase 10 部署 |
| #2 chrome-reaper sidecar | 同上 | ⏳ Phase 10 |
| #2 RSS 監控告警 | scheduler 加每小時 task | ⏳ Phase 10 |
| #3 embedding_signature 欄位 | ai_insights 加欄位 | ✅ migration 026 commit 4648673 |
| #3 簽名計算 | rag_service.get_embedding_signature() | ✅ commit c7d6db3 |
| #3 啟動驗證 verify_consistency | 跨主機 cosine 比對 | ⏳ Phase 11+ 補Phase 11.0 規格) |
| #3 既有 14k 筆回填 | UPDATE ai_insights SET embedding_signature = ... | ⏳ Phase 11+ 補 |
---
## References
- `migrations/026_add_embedding_signature.sql`(含 pgcrypto extension
- `migrations/028_create_learning_episodes.sql`8 狀態機 CHECK
- `services/rag_service.py:get_embedding_signature()`
- `services/learning_pipeline.py`PromotionGate 4 階段)
- `tests/test_promotion_gate.py`23 unit tests
- ADR-002pgvector 唯一)
- ADR-027三主機架構
- ADR-032RAG 自主學習迴圈)
- ADR-031MCP 自建 — Phase 10 將補)

View File

@@ -0,0 +1,176 @@
# ADR-034: Caller × Context 動態 Model Router
- **Status**: Accepted (待整合到 caller 後 Active)
- **Date**: 2026-05-04
- **Decision Maker**: 統帥
- **Author**: Operation Ollama-First v5.0 / Phase 21
- **Related**: ADR-028LLM 路由、ADR-029雙塔分工、ADR-030多供應商
---
## Context
戰役 v5.0 累積完成 Primary + Secondary 兩台 GCP × 各 10 個 Ollama 模型(~67GB。但既有 caller 多用單一寫死 model如 sales_copy 永遠用 `llama3.1:8b`),無法動態根據 context 選最佳 model。
**痛點**
1. **資源浪費**sales_copy 短文(< 100 字)也用 8B 模型 → 應走 `gemma3:4b`4GB vs 5GB延遲 -50%
2. **品質瓶頸**Hermes 競價遇複雜 SKUgap > 20%)仍用 `hermes3:latest`8B→ 應升 `qwen3:14b`
3. **重構斷層**AiderHeal 大型重構diff > 200 行)用 `qwen2.5-coder:7b` 不夠 → 應升 `qwen2.5-coder:32b`
4. **推理空缺**EA HITL 需 chain-of-thought 時無 deepseek-r1 路徑
**前置已完成**
- Primary + Secondary 各 10 模型完整對稱
- `services/llm_caller_registry.py` 30+ caller 集中
- `services/cost_throttle_service.py` 成本守門
本 ADR 鎖定**動態路由規則**設計。
---
## Decision
### 1. 純規則引擎,零 LLM 成本
```python
# services/llm_model_router.py
ROUTING_RULES: Dict[str, list] = {
'sales_copy': [
(lambda ctx: ctx.get('expected_length', 0) < 100, 'gemma3:4b'),
(lambda ctx: True, 'llama3.1:8b'),
],
'hermes_analyst': [
(lambda ctx: ctx['max_gap_pct'] > 20 or ctx['min_sales_delta'] < -50,
'qwen3:14b'),
(lambda ctx: True,
'hermes3:latest'),
],
# ... 6 個 caller 共 12 條規則
}
```
### 2. 路由規則對應表
| Caller | Context 觸發條件 | 升級 Model | 預設 Model |
|---|---|---|---|
| `sales_copy` | expected_length < 100 字 | `gemma3:4b` | `llama3.1:8b` |
| `hermes_analyst` | max_gap_pct > 20% 或 銷量 < -50% | `qwen3:14b` | `hermes3:latest` |
| `aider_heal` | diff_lines > 200 | `qwen2.5-coder:32b` | `qwen2.5-coder:7b` |
| `openclaw_qa` | query_length > 200 或 multi_turn | `qwen3:14b` | `qwen2.5:7b-instruct` |
| `ppt_vision` | minicpm_unhealthy | `llava:latest` | `minicpm-v:latest` |
| `ea_engine` | require_chain_of_thought | `deepseek-r1:14b` | (回 default = Gemini|
### 3. Feature Flag 灰度
- `MODEL_ROUTER_ENABLED` 預設 OFF
- caller 端 `select_model(caller, context, default='既有 model')`
- flag OFF → 直接回 default不評估規則→ 行為與戰前完全相同
### 4. 失敗安全
- predicate 拋例外 → log warning + skip 到下一條
- caller 不在 ROUTING_RULES → 回 default
- 所有規則都不命中 → 回 default
### 5. 整合方式(建議分階段)
```python
# Caller 範例(如 ollama_service.generate_sales_copy
from services.llm_model_router import select_model
def generate_sales_copy(self, product_name, ...):
model = select_model(
caller='sales_copy',
context={'expected_length': len(product_name) * 3},
default='llama3.1:8b',
)
return self.generate(prompt=..., model=model, ...)
```
**戰略性遷移**
- Phase 21.1: model_router service + test 落地(本 commit
- Phase 21.2: sales_copy 整合(低風險示範)⏳
- Phase 21.3: aider_heal 整合(中風險,需 diff_lines 取得)
- Phase 21.4: hermes_analyst 整合(高風險,動戰術主流程)
- Phase 21.5: 全 caller 遷移完成 → MODEL_ROUTER_ENABLED 預設 ON
---
## Alternatives Considered
| 方案 | 否決理由 |
|---|---|
| **A. LLM-based routing**(用 LLM 決定用哪個 model| 循環燒錢 + 引入新延遲 |
| **B. caller 各自 hardcode 多 model**(不集中)| 規則漂移無 single source of truth |
| **C. 直接統一升級到大模型**(如全用 qwen3:14b| 浪費資源,短文不需 14B |
| **D. 配置檔 YAML/JSON**(運行時讀檔)| 過度工程Python lambda 已夠彈性 |
---
## Consequences
### 正面5
1. **資源節省**:短文 sales_copy 用 4GB gemma3 vs 5GB llama3.1,延遲 -50%
2. **品質提升**複雜場景自動升大模型hermes 14B / aider 32B
3. **零 LLM 成本**:純 Python lambda 規則
4. **失敗安全**:規則例外不阻擋主流程
5. **集中治理**:規則改動只需 PR `llm_model_router.py`,不動 caller
### 負面3
1. **規則維護成本**:新 caller / 新 context 條件需更新 rules但這正是 ADR 治理目標)
2. **context 取得負擔**caller 必須先計算 context如 diff_lines才能呼叫 router
3. **debug 複雜度**:路由命中哪條規則需看 logger.debug
### 風險3
1. **規則設計失誤**閾值20% / 200 lines可能不準 → mitigate by Phase 21.2-21.5 灰度觀察
2. **GCP 主機沒拉到對應 model**select 回的 model 不存在 → mitigate by 拉模型前提(已完成 10 模型對稱)
3. **caller 整合不完整**:部分 caller 仍 hardcode → 文件化遷移計畫
---
## Verification
### V1unit test
```bash
pytest tests/test_llm_model_router.py -v
# 預期 18 tests 全綠
```
### V2caller 整合後 ai_calls 觀察
```sql
SELECT model, COUNT(*), AVG(duration_ms)
FROM ai_calls
WHERE caller = 'sales_copy' AND called_at > NOW() - INTERVAL '7 days'
GROUP BY model;
-- 期望gemma3:4b 短文佔 60%+llama3.1:8b 長文佔 40%-
-- 平均 duration: gemma3 < llama3.1 約 50%
```
### V3cost throttle 整合
```python
# Phase 22 規劃cost_throttle 觸發時自動切便宜 model
# 例claude throttled → select_model 改回 default Gemini Flash
```
---
## Migration Plan
| Phase | 工作 | 狀態 |
|---|---|---|
| 21.1 | services/llm_model_router.py + 18 tests | ✅ 本 commit |
| 21.2 | sales_copy 整合generate_sales_copy 加 select_model| ⏳ |
| 21.3 | aider_heal 整合(需 diff_lines context| ⏳ |
| 21.4 | hermes_analyst 整合(需 max_gap_pct context| ⏳ |
| 21.5 | openclaw_qa / ppt_vision / ea_engine | ⏳ |
| 21.6 | MODEL_ROUTER_ENABLED 預設 ON觀察 1 週後)| ⏳ |
---
## References
- `services/llm_model_router.py`(本 commit
- `tests/test_llm_model_router.py`18 tests
- `docs/llm_model_full_evaluation_20260504.md` 路由優化建議
- ADR-028LLM 路由統一準則)
- ADR-029Hermes-First 雙塔分工)
- ADR-030Frontier 多供應商策略)

View File

@@ -0,0 +1,307 @@
# ADR-035: 跨平台市場活動情報系統
- **狀態**: Accepted
- **日期**: 2026-05-06
- **觸發**: 使用者提出定期掌握 MOMO / 蝦皮 / 酷澎 / PChome 等電商活動檔期、活動商品、競品價格與資料庫保存需求
- **相關 ADR**: ADR-011跨專案資源隔離、ADR-017模組化收尾路線圖、ADR-025市場情報週報
- **相關 Memory**: `docs/memory/code_modularization_inventory_20260430.md`
## Context
EwoooC 目前已有 MOMO EDM / 節慶活動資料、`promo_products`、PChome 競品價格 feeder、PPT 市場情報週報與多個分析頁,但跨平台活動情報尚未形成獨立資料模型與可維護爬蟲框架。
若直接把蝦皮、酷澎、PChome 等平台資料塞進既有 `promo_products``routes/sales_routes.py``scheduler.py` 或分析頁大型 template會造成下列風險
1. 不同平台欄位語意不同,舊表無法承載活動檔期、平台商品 ID、折扣券、銷售訊號與價格歷史。
2. 既有 `scheduler.py``routes/sales_routes.py``routes/dashboard_routes.py`、多個 crawler service 已達大檔治理門檻,新增功能會加劇技術債。
3. 新爬蟲若直接上正式排程,可能造成 DB 寫入量、外部平台 rate limit、排程阻塞與告警噪音。
4. 新市場情報頁若複製既有巨型 Jinja template 模式,會延續 UI token、字體、色彩與點陣風格不一致問題。
## Decision
建立新的 **跨平台市場活動情報系統**,採分階段落地、預設關閉、可獨立回退的方式推進。
### 1. 模組邊界
新功能必須使用獨立模組,不得塞回既有巨檔:
- `services/market_intel/`:活動探索、商品爬取、正規化、商品比對、告警摘要。
- `services/market_intel/adapters/`:各平台 adapter例如 MOMO / PChome / Coupang / Shopee。
- `database/market_intel_models.py``market_*` ORM models。
- `routes/market_intel_routes.py`:市場情報頁面與 API route glue。
- `templates/market_intel/`:市場情報 UI template。
- `services/scheduler/` 或獨立 job module市場情報排程掛載點。
### 2. 資料模型
新增 `market_*` schema 作為唯一主資料層:
- `market_platforms`
- `market_campaigns`
- `market_campaign_snapshots`
- `market_campaign_products`
- `market_product_price_history`
- `market_product_matches`
- `market_crawler_runs`
- `market_alert_review_queue`
`promo_products` 只作為既有 MOMO 活動資料的相容來源或雙寫過渡,不再承接跨平台唯一真相。
### 3. Feature Flag 與啟用策略
市場情報第一階段必須預設關閉:
- `MARKET_INTEL_ENABLED=false`
- `MARKET_INTEL_CRAWLER_ENABLED=false`
- `MARKET_INTEL_WRITE_ENABLED=false`
初期允許 dry-run建立 run log、解析活動與商品但不大量寫入正式商品資料。正式入庫與排程啟用需另行通過 smoke test、rate limit 驗證與 rollback drill。
### 4. 爬蟲安全邊界
市場情報爬蟲只允許抓公開頁面或公開結構化資料,不做登入、不碰會員資料、不破解反爬、不使用帳號池、不繞付費牆。
每平台 adapter 必須具備:
- rate limit
- timeout
- retry ceiling
- user-agent 與來源識別
- run log
- error classification
- dry-run mode
- 可單平台停用開關
### 5. UI / UX 邊界
市場情報 UI 不複製巨型分析頁模式,必須先抽共用元件與設計 token
- 活動檔期看板
- 活動商品池
- 商品比對審核
- 市場機會與威脅
所有新頁必須符合 V2 暖紙、暖墨、焦糖 accent、等寬數字、點陣紋理與真實資料規範。未串接資料時只能顯示可診斷空狀態不得使用假商品或假 KPI。
### 6. 上線與回退
部署遵守 ADR-011
- 禁止 `docker compose ... --remove-orphans`
- 禁止影響 `momo-db` 容器生命週期
- 只用 `docker compose up -d --no-deps --force-recreate <service>` 精準重建
- health check 只打 `/health`
異常回退順序:
1. 關閉 `MARKET_INTEL_*` feature flags。
2. 停用市場情報 scheduler job。
3. 保留 `market_*` 表與 run log不刪資料。
4. 回復上一版 route / service 程式碼。
5. 僅重啟受影響應用容器,不動 DB。
## Phased Rollout
### Phase 0Readiness Audit
- 更新模組化 inventory。
- 確認 `scheduler.py` 無 conflict marker 且可 py_compile。
- 標記市場情報不可寫入的既有大檔。
- 完成 ADR-035。
### Phase 1Skeleton Only
- 新增 feature flags。
- 新增 `market_intel` package skeleton。
- 新增空 route / disabled page / dry-run service。
- 不啟用正式排程,不大量入庫。
### Phase 2DB Schema
- 新增 `market_*` ORM models。
- 補 metadata import 與 schema smoke。
- 寫入 crawler run log 與少量 dry-run snapshot。
### Phase 3MOMO / PChome Adapter
- 先接成本最低且已有脈絡的平台。
- 只抓公開活動入口與活動商品。
- 建立活動與商品正規化規則。
- 2026-05-06 起先落地 read-only adapter skeleton只註冊平台入口與安全策略不發 HTTP request、不寫 DB、不掛 scheduler。
- 2026-05-06 追加手動 dry-run discovery runner`fetch=false` 只回 planned`fetch=true``MARKET_INTEL_ENABLED``MARKET_INTEL_CRAWLER_ENABLED` 同時開啟,且仍禁止 DB write 與 scheduler attach。
- 2026-05-06 追加 parser 診斷層:成功手動 fetch 後只輸出 title、page_hash、link counts 與 campaign link candidates不得建立正式 campaign/product。
- 2026-05-06 追加平台別 scorerMOMO/PChome adapter 可對 URL/text 加權diagnostics 需保留 `generic_score``platform_score` 供人工判讀,不得自動建檔期。
- 2026-05-06 追加 confidence bands候選連結只可標記 `high` / `medium` / `low``confidence_reason` 作為人工審核提示,不得自動建立 campaign。
- 2026-05-06 追加 candidate preview API只聚合本次 diagnostics 的候選連結並支援 `min_band` / `limit`,不得入庫或自動建立活動。
- 2026-05-06 追加 UI preview panel市場情報頁只讀同站 `/api/market_intel/candidate_preview?fetch=false` 顯示安全空狀態,不得自動外部 fetch。
- 2026-05-06 追加 platform seed plan`/api/market_intel/platform_seed_plan` 只把 adapter registry 轉為可審核 seed rows正式 upsert `market_platforms` 仍需 migration、schema smoke、feature flag 與人工批准。
- 2026-05-06 追加 Coupang read-only adapter以官方台灣站 `https://www.tw.coupang.com/``https://www.tw.coupang.com/np/coupangglobal` 作為公開 discovery 起點;預設仍不發 request、不寫 DB、不掛 scheduler。
- 2026-05-07 追加 Shopee read-only adapter`https://shopee.tw/``https://shopee.tw/mall` 作為公開 discovery 起點;不得登入、處理會員券/購物車、使用帳號池或繞過反爬。
- 2026-05-07 追加 Phase 12 UI QA本機 harness 載入 `/market_intel`,確認 4 adapter planned、console error 0、窄版 in-app browser 未水平爆版;真 390px 截圖需後續使用可設定 viewport 的 runner 補驗。
- 2026-05-07 追加 platform seed write guard`/api/market_intel/platform_seed_write_guard` 只回報 feature flag、migration、schema smoke、人工批准 gate 狀態,預設永遠不寫 DB。
- 2026-05-07 追加 platform seed writer dry-run`/api/market_intel/schema_smoke` 實際檢查 ORM metadata`/api/market_intel/platform_seed_writer_plan` 只產生 parameterized `market_platforms` upsert preview不建立 session、不 commit。
- 2026-05-07 追加 writer preview panel市場情報頁讀取同站 `/api/market_intel/platform_seed_writer_plan`,顯示 schema smoke、upsert preview 與 blocked reasons仍不得寫 DB。
- 2026-05-07 追加 deployment readiness panel`/api/market_intel/deployment_readiness` 與 UI 明確回報尚未正式推版、尚未 commit/push、部署 SOP 與 production smoke 尚待人工執行。
- 2026-05-07 追加 deployment handoff checklistreadiness API/UI 顯示人工推版步驟、備援方案、安全部署邊界、production smoke targets 與 `python backup_system.py` 備份要求;此階段仍不執行 git、部署、DB 或外部爬取動作。
- 2026-05-07 追加 write approval runbook`/api/market_intel/write_approval_runbook` 與 UI 顯示正式 seed write 前 gate、operator sequence、rollback plan 與硬性安全邊界;預設不建立 DB session、不 commit、不連外、不掛 scheduler。
- 2026-05-07 追加 migration blueprint`/api/market_intel/migration_blueprint` 與 UI 顯示 `migrations/032_market_intel_core_schema.sql` 草案、migration apply command shape 與 seed writer command design此階段仍不建立 migration 檔、不執行 SQL、不寫 seed rows。
- 2026-05-07 追加 migration file draft建立本地 `migrations/032_market_intel_core_schema.sql` 草稿檔blueprint API 會檢查檔案存在且內容與草案相符,但仍不執行 SQL、不建立 DB session、不寫 seed rows。
- 2026-05-12 追加 seed writer CLI skeleton`scripts/market_intel_seed_writer.py``/api/market_intel/seed_writer_cli_status` 只輸出 blocked plan即使收到 `--execute` 與一次性 approval token 也不建立 DB session、不 commit、不寫 seed rows。
- 2026-05-12 追加 app-only release gate`/api/market_intel/deployment_readiness` 區分「安全檢查可進 app-only 推版」與「API 不執行部署」;即使 `ready_for_production_deploy=true`,仍不得由 API 執行 git、備份、scp、ssh、container recreate、migration 或 DB write。
- 2026-05-12 追加 seed transaction preview`/api/market_intel/seed_writer_cli_status` 會輸出 `transaction_preview`,包含 idempotent upsert SQL template、parameter payload hash 與 diff 狀態;此預覽不得載入既有 DB rows、不得開 transaction、不得 commit。
- 2026-05-12 追加 read-only DB schema probe`/api/market_intel/schema_db_probe` 預設只回 planned不連 DB人工 smoke 才能以明確參數查正式 DB catalog。探針不得使用 `DatabaseManager()`,避免觸發 metadata `create_all()`;不得建立 ORM session、不得寫入、不得 commit。
- 2026-05-12 追加 platform seed DB diff probe`/api/market_intel/platform_seed_db_diff` 預設只回 planned不連 DB人工 smoke 才能以明確參數只讀查詢 `market_platforms`,比對 adapter seed 是否 missing / differs / matches。探針不得使用 `DatabaseManager()`、不得建立 ORM session、不得寫入、不得 commit。
- 2026-05-13 追加 platform seed CLI writer`scripts/market_intel_seed_writer.py` 可在 CLI 明確帶入 `--execute``--apply-real-write` 與確認 token 時,以 SQLAlchemy Core 短 transaction upsert `market_platforms`API 仍不得替使用者執行 DB 寫入,不建立 ORM session、不連外、不掛 scheduler。
- 2026-05-18 追加 legacy source bridge preview`/api/market_intel/legacy_source_bridge` 預設 `execute=false` 只回 planned不連 DB人工 smoke 才能以 `execute=true` 只讀盤點 `promo_products``competitor_prices``competitor_price_history`,產生舊資料導入 `market_*` 的 mapping、dedupe 與 blocked operation preview。此橋接不得寫入 DB、不得建立 ORM session、不得把 PChome 比價快取冒充為活動頁商品、不得掛 scheduler。
- 2026-05-18 追加 MCP readiness preview`/api/market_intel/mcp_readiness` 預設 `execute=false` 只回 planned盤點 ADR-031 外部 MCP server、`services.mcp_router` feature flag、tool registry、`mcp_calls` telemetry 與 market_intel tool contract 缺口。人工 smoke 才能以 `execute=true` 做只讀 health / telemetry probe此探針不得寫 DB、不得建立 ORM session、不得替市場情報自動啟用 MCP 或外部爬取。
- 2026-05-18 追加 internal MCP tool contract preview`services.market_intel.mcp_contract``/api/market_intel/mcp_tool_contract` 定義 `market_campaign_search``market_campaign_scrape``market_product_match_lookup` 三個 read-only contract並在 `services.mcp_router.TOOL_REGISTRY` 註冊 `market_intel` caller 白名單。此階段只建立可審核合約與 readiness 檢查,不啟用 `MCP_ROUTER_ENABLED`、不呼叫 MCP server、不寫 DB、不掛 scheduler。
- 2026-05-18 追加 external MCP deploy preflight preview`services.market_intel.mcp_deploy_preflight``/api/market_intel/mcp_deploy_preflight` 只讀檢查 `docker-compose.mcp.yml`、必要 env、localhost-only ports、read-only volume、Firecrawl resource guard 與 fallback plan。`docker-compose.mcp.yml` 需以 read-only bind mount 進 app 容器供 preflight 審核。此 preflight 不執行 docker/SSH、不建立 `mcp_readonly` role、不啟用 `MCP_ROUTER_ENABLED`、不寫 DB、不掛 scheduler外部 MCP stack 須等 env 與 operator smoke 全過後另行批准。
- 2026-05-18 追加 MCP activation runbook preview`services.market_intel.mcp_activation_runbook``/api/market_intel/mcp_activation_runbook` 只輸出人工啟用順序與 gate補必要 env、人工建立/驗證 `mcp_readonly`、啟動外部 MCP stack、四個 health 全過、最後才允許 `MCP_ROUTER_ENABLED=true`。此 runbook 不執行 docker/SSH、不寫 env、不建立 DB role、不跑 health、不啟用 router、不寫 DB、不掛 scheduler。
- 2026-05-18 追加 MCP fetch gate preview`services.market_intel.mcp_fetch_gate``/api/market_intel/mcp_fetch_gate` 將人工 discovery fetch 改成必須先通過市場情報 feature flags、MCP readiness、router、外部 MCP health 與 tool contract gate`run_manual_discovery(fetch=true)` 即使 flags 開啟也會先被此 gate 阻擋,直到 MCP 條件全過。此 gate 不抓電商頁、不寫 DB、不掛 scheduler、不執行 deploymentUI 預設只呼叫 `fetch=false&execute=false`
- 2026-05-24 追加 MCP manual fetch handoff gate`services.market_intel.mcp_manual_fetch_handoff``/api/market_intel/mcp_manual_fetch_handoff` 將 runtime promotion package 與操作員安全確認合併成可審核 handoff只放行到人工 fetch gate operator reviewAPI/UI 不保存 payload、不打 health、不開 DB、不抓外站、不掛 scheduler也不會自動打開 manual fetch。
- 2026-05-24 追加 MCP fetch target review gate`services.market_intel.mcp_fetch_target_review``/api/market_intel/mcp_fetch_target_review` 在 manual fetch handoff 後審核 adapter registry 公開入口白名單、平台來源、每平台 delay / timeout / max pages / sample_limit、rollback plan 與操作員確認API/UI 不保存 payload、不發外部 request、不開 DB、不寫入、不掛 scheduler也不會自動打開 manual fetch只放行到後續人工 fetch run package review。
- 2026-05-24 追加 MCP fetch run package gate`services.market_intel.mcp_fetch_run_package``/api/market_intel/mcp_fetch_run_package` 將已通過的 target review 轉成 command argv preview、receipt path 與操作員 run controls 審核包;路由拆至 `routes.market_intel_mcp_run_routes`,主 Blueprint 僅掛 extension import。此階段不執行 CLI、不發外部 request、不寫 artifact、不開 DB、不掛 scheduler只放行到後續 run readiness review。
- 2026-05-24 追加 MCP fetch run readiness gate`services.market_intel.mcp_fetch_run_readiness``/api/market_intel/mcp_fetch_run_readiness` 在 run package 後檢查 command preview、receipt path、artifact path、節流/timeout/dry-run-first、secret payload 與操作員 shell-only 邊界;此階段不執行 CLI、不發外部 request、不寫 artifact、不開 DB、不掛 scheduler只放行到人工 shell dry-run 與後續 receipt review。
- 2026-05-29 追加 MCP fetch run receipt gate`services.market_intel.mcp_fetch_run_receipt``/api/market_intel/mcp_fetch_run_receipt` 在操作員 shell 完成 dry-run fetch 後審核 receipt id、artifact path、platform/source/receipt path 對帳、公開 URL、request/error budget、secret 外洩與 API/DB/scheduler 副作用旗標API/UI 不執行 CLI、不發外部 request、不保存 receipt、不開 DB、不寫入、不掛 scheduler只放行到後續 result parser review。
- 2026-05-31 追加 MCP fetch result parser review gate`services.market_intel.mcp_fetch_result_parser_review``/api/market_intel/mcp_fetch_result_parser_review` 在 receipt 通過後審核操作員貼回的 parser 結構化摘要,檢查 receipt source/receipt path 對帳、parser artifact path、活動/商品候選必要欄位、公開 URL、小批次候選上限、raw HTML/secret 外洩與 API/DB/scheduler 副作用旗標API/UI 不讀 artifact、不執行 parser CLI、不發外部 request、不保存 parser result、不寫入、不掛 scheduler只放行到候選 handoff review。
- 2026-05-31 追加 MCP fetch candidate handoff review gate`services.market_intel.mcp_fetch_candidate_handoff_review``/api/market_intel/mcp_fetch_candidate_handoff_review` 在 parser review 通過後審核候選交接包,檢查 source/candidate key 對齊、queue policy 是否仍是 `manual_candidate_review` / `preview_only`、小批次候選上限、操作員無寫入/無連外/無排程確認、raw HTML/secret 外洩與 side-effect flagsAPI/UI 不建立 queue、不讀 artifact、不寫 DB、不掛 scheduler只放行到人工 candidate queue review。
- 2026-05-31 追加 MCP fetch candidate queue review gate`services.market_intel.mcp_fetch_candidate_queue_review``/api/market_intel/mcp_fetch_candidate_queue_review` 在 handoff review 通過後審核人工 queue review 草案,檢查候選 key 對齊、`review_state=needs_review`、allowed actions 人工限定、`queue_write_status=not_persisted`、操作員無寫入/無連外/無排程確認、raw HTML/secret 外洩與 side-effect flagsAPI/UI 不建立 queue、不更新 review_state、不讀 artifact、不寫 DB、不掛 scheduler只放行到 writer preflight。
- 2026-05-31 追加 MCP fetch candidate queue writer preflight gate`services.market_intel.mcp_fetch_candidate_queue_writer_preflight``/api/market_intel/mcp_fetch_candidate_queue_writer_preflight` 在 queue review 通過後審核 writer preflight 草案,檢查 `target_table=market_alert_review_queue``write_mode=cli_only_later`、dedupe strategy、insert columns、payload rows、候選 key 對齊、小批次上限、操作員無寫入/無連外/無 CLI/無排程確認、raw HTML/secret 外洩與 side-effect flagsAPI/UI 不開 DB、不執行 CLI、不建立 queue、不更新 review_state、不寫 DB、不掛 scheduler只放行到 CLI writer review。
- 2026-05-31 追加 MCP fetch candidate queue writer CLI review gate`services.market_intel.mcp_fetch_candidate_queue_writer_cli_review``/api/market_intel/mcp_fetch_candidate_queue_writer_cli_review` 在 writer preflight 通過後審核 CLI review 草案,檢查 script path、target table、preflight id、payload row count、candidate/dedupe keys、`--sample-json``--read-only-preflight` 與 forbidden flagsAPI/UI 不執行 CLI、不讀 approval token、不寫檔、不開 DB、不寫 queue、不掛 scheduler只放行到 operator run package review。
- 2026-05-31 追加 MCP fetch candidate queue writer run package review gate`services.market_intel.mcp_fetch_candidate_queue_writer_run_package_review``/api/market_intel/mcp_fetch_candidate_queue_writer_run_package_review` 在 CLI review 通過後審核 operator run package 草案,檢查 package identity、artifact manifest、operator shell command sequence、candidate/dedupe keys、CLI review id 與 preflight idAPI/UI 不產檔、不讀 approval token、不執行 CLI、不開 DB、不寫 queue、不掛 scheduler只放行到 run readiness review。
- 2026-05-31 追加 MCP fetch candidate queue writer run readiness gate`services.market_intel.mcp_fetch_candidate_queue_writer_run_readiness``/api/market_intel/mcp_fetch_candidate_queue_writer_run_readiness` 在 run package review 通過後審核 operator readiness 證據,檢查 run readiness artifact、reviewed sample、備份、read-only preflight、post-write smoke 路徑、操作員覆核確認、CLI-only 與 approval token shell-only 邊界API/UI 不產檔、不讀 approval token、不執行 CLI、不開 DB、不寫 queue、不掛 scheduler只放行到後續 run receipt review。
- 2026-05-31 追加 MCP fetch candidate queue writer run receipt review gate`services.market_intel.mcp_fetch_candidate_queue_writer_run_receipt_review``/api/market_intel/mcp_fetch_candidate_queue_writer_run_receipt_review` 在 run readiness 通過後審核 operator shell writer run 的 receipt 摘要,檢查 readiness linkage、run package id、候選/dedupe keys、writer output artifact、post-write smoke artifact、backup path、operator confirmations 與 token redactionAPI/UI 不讀 receipt 原文、不讀 approval token、不執行 CLI、不開 DB、不寫 queue、不做 post-write query、不掛 scheduler只放行到 closeout review。
- 2026-05-31 追加 MCP fetch candidate queue writer run closeout review gate`services.market_intel.mcp_fetch_candidate_queue_writer_run_closeout_review``/api/market_intel/mcp_fetch_candidate_queue_writer_run_closeout_review` 在 receipt review 通過後審核 operator closeout 摘要,檢查 receipt linkage、closeout artifact、receipt review artifact、post-closeout inventory plan、writer output / post-write smoke / backup manifest、rollback note 與 operator confirmationsAPI/UI 不讀 receipt 原文、不讀 approval token、不執行 CLI、不開 DB、不寫 queue、不做 post-closeout query、不掛 scheduler只放行到 read-only post-closeout inventory review。
- 2026-05-31 追加 MCP fetch candidate queue writer post-closeout inventory review gate`services.market_intel.mcp_fetch_candidate_queue_writer_post_closeout_inventory_review``/api/market_intel/mcp_fetch_candidate_queue_writer_post_closeout_inventory_review` 在 closeout review 通過後審核 operator live inventory read-only 摘要,檢查 closeout linkage、row count、inventory artifact、closeout review artifact、read-only query result、missing/duplicate rows 與 operator confirmationsAPI/UI 不讀 approval token、不執行 CLI、不開 DB、不寫 queue、不做 inventory query、不掛 scheduler只放行到 candidate queue review handoff。
- 2026-05-31 追加 MCP fetch candidate queue writer review handoff gate`services.market_intel.mcp_fetch_candidate_queue_writer_review_handoff``/api/market_intel/mcp_fetch_candidate_queue_writer_review_handoff` 在 post-closeout inventory review 通過後審核 operator candidate queue review handoff 摘要,檢查 inventory linkage、handoff identity、target table、row count、artifact paths、review contract、forbidden API actions 與 operator confirmationsAPI/UI 不讀 approval token、不執行 CLI、不開 DB、不寫 queue、不更新 review_state、不掛 scheduler只放行到人工 candidate queue review。
- 2026-05-31 追加 MCP fetch candidate queue writer review inventory gate`services.market_intel.mcp_fetch_candidate_queue_writer_review_inventory``services.market_intel.mcp_fetch_candidate_queue_writer_review_inventory_gates``services.market_intel.mcp_fetch_candidate_queue_writer_review_inventory_sample``/api/market_intel/mcp_fetch_candidate_queue_writer_review_inventory` 在 writer review handoff 通過後審核 operator read-only candidate queue inventory 摘要,檢查 handoff identity、target table、row count、dedupe keys、review_state、artifact paths、read-only query result、missing/duplicate rows 與 operator confirmationsAPI/UI 不讀 approval token、不執行 CLI、不開 DB、不寫 queue、不更新 review_state、不做 inventory query、不掛 scheduler只放行到後續人工 candidate queue review。
- 2026-05-31 追加 MCP fetch candidate queue writer review decision gate`services.market_intel.mcp_fetch_candidate_queue_writer_review_decision``services.market_intel.mcp_fetch_candidate_queue_writer_review_decision_gates``services.market_intel.mcp_fetch_candidate_queue_writer_review_decision_sample``/api/market_intel/mcp_fetch_candidate_queue_writer_review_decision` 在 review inventory 通過後審核 operator candidate queue review decision 摘要,檢查 decision identity、target table、row count、dedupe keys、`needs_review` 現態、允許決策集合、evidence refs、matched row exact-identity/variant/overwrite guard、operator confirmations 與 forbidden API actionsAPI/UI 不讀 approval token、不執行 CLI、不開 DB、不寫 decision record、不更新 review_state、不寫 match result、不補 queue、不掛 scheduler只放行到 decision approval / writer preflight 設計。
- 2026-05-31 追加 MCP fetch candidate queue writer review decision approval gate`services.market_intel.mcp_fetch_candidate_queue_writer_review_decision_approval``services.market_intel.mcp_fetch_candidate_queue_writer_review_decision_approval_gates``services.market_intel.mcp_fetch_candidate_queue_writer_review_decision_approval_sample``/api/market_intel/mcp_fetch_candidate_queue_writer_review_decision_approval` 在 review decision 通過後只審核 operator human approval 摘要,確認 decision linkage、approval identity、target table、row count、dedupe keys、`approved_for_writer_preflight` approval result、decision/approval evidence refs、artifact paths、matched row exact-identity/variant/overwrite guard、operator confirmations 與 forbidden API actionsAPI/UI 不讀 approval token、不執行 CLI、不開 DB、不寫 approval record、不寫 decision record、不更新 review_state、不寫 match result、不補 queue、不掛 scheduler只放行到後續 writer preflight 設計。此 endpoint 已拆入 `routes.market_intel_mcp_review_routes`,避免 `routes.market_intel_mcp_run_routes` 超過 800 行治理門檻。
- 2026-05-31 追加 MCP fetch candidate queue writer review decision approval writer preflight gate`services.market_intel.mcp_fetch_candidate_queue_writer_review_decision_approval_writer_preflight`、對應 gates/sample 與 `/api/market_intel/mcp_fetch_candidate_queue_writer_review_decision_approval_writer_preflight` 在 human approval 通過後只審核 operator writer preflight 摘要,確認 approval linkage、writer_preflight_id、target operation、row count、dedupe keys、approved decision 到 target review_state 的逐列映射、decision/approval/preflight evidence refs、matched row exact-identity/variant/overwrite guard 與 operator boundaryAPI/UI 不讀 approval token、不執行 CLI、不開 DB、不寫 preflight/approval/decision/match、不更新 review_state、不補 queue、不掛 scheduler只放行到後續 CLI review / run package 設計。
- 2026-06-01 追加 Professional Source Governance gate`services.market_intel.mcp_professional_source_governance`、對應 gates/sample 與 `/api/market_intel/mcp_professional_source_governance` 將 robots/REP、sitemap/lastmod、JSON-LD / schema.org structured data、canonical URL、rate limit、公開資料邊界、provenance、snapshot hash 與 idempotency key 整理為 source contract。此 gate 只審核 operator source governance 摘要,不抓外站、不讀 robots/sitemap、不開 DB、不寫檔、不掛 scheduler後續 fetch target review 才能引用通過治理的公開來源。
- 2026-06-03 追加 Source Governance → Fetch Target bridge`services.market_intel.mcp_fetch_target_source_governance_review``/api/market_intel/mcp_fetch_target_source_governance_review` 只交叉審核已通過治理的 source contract 與 MCP Fetch Target Review要求每個 target `platform_code/source_key` 都命中治理摘要;仍不執行外部 fetch、不讀 robots/sitemap、不開 DB、不寫檔、不執行 CLI、不掛 scheduler。
- 2026-05-18 追加 scheduler attach plan preview`services.market_intel.scheduler_plan``/api/market_intel/scheduler_plan` 描述未來 `campaign_discovery_daily``campaign_product_probe``product_match_review_seed` 三個 job 的 cadence、gate、fallback 與安全邊界。此階段不註冊 scheduler job、不啟動 crawler、不連外、不寫 DB排程掛載必須等 migration、seed、MCP fetch gate、manual sample 與人工批准全過。
- 2026-05-18 追加 match review plan preview`services.market_intel.match_review_plan``/api/market_intel/match_review_plan` 定義商品比對訊號、分數門檻、`needs_review → confirmed/rejected` HITL 流程與安全邊界。此階段不建立 review queue、不自動 confirmed、不寫 `market_product_matches`、不呼叫 MCP價格只能作為輔助訊號不能單獨決定同品比對。
- 2026-05-18 追加 opportunity plan preview`services.market_intel.opportunity_plan``/api/market_intel/opportunity_plan` 定義競品低價威脅、促銷缺口、深折重疊、活動即將結束四類規則與分級策略。此階段不建立 opportunity queue、不派送 Telegram、不產生 AI 摘要、不寫 DB高風險項必須先有 confirmed match 與 DB evidence 才能升級。
- 2026-05-18 追加 opportunity scoring plan preview`services.market_intel.opportunity_scoring``/api/market_intel/opportunity_scoring_plan` 定義價差、折扣深度、比對可信度、活動急迫性與資料新鮮度五個 scoring dimensions、分級門檻、evidence tables 與人工升級順序。此階段不計分、不產生 sample scores、不建立 scoring job、不寫 DB、不派送 Telegram、不產生 AI 摘要。
- 2026-05-18 追加 opportunity evidence plan preview`services.market_intel.opportunity_evidence``/api/market_intel/opportunity_evidence_plan` 定義 scoring / alert / AI 摘要必須攜帶的 campaign、market product、match review、MOMO reference、scoring trace 五段 evidence bundle contract。此階段不查 DB、不產生 sample evidence、不建立 alert candidate、不派送 Telegram、不產生 AI 摘要。
- 2026-05-18 追加 opportunity alert plan preview`services.market_intel.opportunity_alerts``/api/market_intel/opportunity_alert_plan` 定義人工審核、每日摘要、Telegram 候選、AI 摘要候選四種 channel 的最低門檻、去重節流、payload contract 與操作順序。此階段不建立 alert queue、不派送 Telegram、不呼叫 LLM、不寫 DB所有告警必須先有 evidence bundle、dedupe key 與人工批准。
- 2026-05-18 追加 opportunity alert review preview`/api/market_intel/opportunity_alert_plan` 擴充人工審核狀態與操作,定義 `draft → needs_review → approved_for_digest / approved_for_telegram / rejected / deferred` 流程、審核理由、審核者身分與派送前二次 gate。此階段不建立 review queue、不執行審核動作、不寫 approval record、不派送 Telegram、不呼叫 LLM。
- 2026-05-18 追加 deployment readiness modularization`/api/market_intel/deployment_readiness` 的大型 app-only release gate 組裝邏輯由 `services.market_intel.service` 拆至 `services.market_intel.deployment_readiness`,主服務保留薄入口,避免後續 crawler / MCP / 審核功能推進時超過 800 行治理線;行為仍維持 preview-only不執行 git、部署、SSH、migration 或 DB write。
- 2026-05-18 追加 alert review queue contract`/api/market_intel/opportunity_alert_plan` 補上 `market_alert_review_queue` 的 preview contract、required / audit / forbidden fields、priority lanes 與索引規劃。此階段只定義資料契約,不建立 review table、不寫 queue contract、不執行審核、不派送 Telegram、不呼叫 LLM。
- 2026-05-18 追加 alert review queue migration blueprint`market_alert_review_queue` 納入 `database/market_intel_models.py``migrations/032_market_intel_core_schema.sql` 與 migration blueprint補齊 additive CREATE TABLE / index / grant / rollback draft。此階段仍不執行 migration、不連 DB、不建立 review queue、不寫入審核資料。
- 2026-05-18 追加 migration apply drill preview`services.market_intel.migration_drill``/api/market_intel/migration_apply_drill` 集中正式 migration 前的只讀 schema probe、platform seed diff、人工套用清單、post-apply smoke、回滾演練與風險清單。預設 `execute=false` 不連 DB人工 smoke 可用 `execute=true` 觸發只讀 catalog / seed diff probe但仍不執行 psql、不跑 rollback、不寫 DB、不重啟容器、不掛 scheduler。
- 2026-05-18 追加 migration catalog review preview`services.market_intel.migration_catalog_review``/api/market_intel/migration_catalog_review` 將 schema_db_probe 與 platform_seed_db_diff 的只讀結果歸納為 `planned_no_probe` / `not_applied` / `partial_schema` / `already_applied` / `probe_error`,並輸出 risk level、apply path、finding 與下一步。預設 `execute=false` 不連 DB`execute=true` 仍只查 catalog / seed diff不執行 psql、不寫 DB、不跑 rollback、不掛 scheduler。
- 2026-05-18 追加 migration live smoke preview`services.market_intel.migration_live_smoke``/api/market_intel/migration_live_smoke``execute=true` 的正式 DB 只讀探測整理成 smoke result例如 `passed_not_applied_seed_table_missing``attention_partial_schema``passed_already_applied``failed_catalog_probe_error`。UI 預設仍只呼叫 `execute=false`;人工 smoke 可用 `execute=true` 只讀查 catalog不執行 migration、不寫 DB、不跑 rollback、不掛 scheduler。
- 2026-05-18 追加 live DB inventory preview`services.market_intel.live_db_inventory``/api/market_intel/live_db_inventory` 預設 `execute=false` 只回 planned不連 DB人工 smoke 可用 `execute=true``market_*` tables 執行只讀 count / group by產生平台、活動狀態、商品活躍度、比對狀態、告警審核佇列與 crawler run 基準總覽。此探針不建立 ORM session、不寫 DB、不執行 migration、不連外、不掛 scheduler。
- 2026-05-19 追加 manual sample fetch plan preview`services.market_intel.manual_sample_plan``/api/market_intel/manual_sample_plan` 定義第一次人工 sample fetch 的平台順序、每平台 1 個公開入口、MCP fetch gate、正式 DB 庫存基準、操作員步驟與備援。此階段只產生計畫,不抓外部網站、不寫 DB、不建立 crawler run、不掛 scheduler、不繞反爬。
- 2026-05-19 追加 manual sample acceptance contract`services.market_intel.manual_sample_acceptance``/api/market_intel/manual_sample_acceptance` 定義 sample fetch 結果回來後的必要欄位、診斷欄位、驗收門檻、拒收條件、人工決策與升級順序。此階段不載入 sample result、不抓外部網站、不允許候選導入、不寫 DB、不掛 scheduler。
- 2026-05-19 追加 manual sample result review`services.market_intel.manual_sample_review``/api/market_intel/manual_sample_review` 以純函式評估操作員提供的 sample result 是否通過 Phase 48 驗收門檻並可進候選預覽。API/UI 預設不載入 sample result不抓外站、不存檔、不寫 DB、不允許候選導入、不掛 scheduler即使審核通過也只開 candidate preview gate正式 market_* 寫入仍需後續獨立批准。
- 2026-05-19 追加 manual sample review evaluate`/api/market_intel/manual_sample_review/evaluate` 提供 POST-only 即時審核入口,操作員可貼入單筆 sample result JSON 取得 PASS/BLOCK 與 candidate preview readiness。此入口不保存 payload、不回吐完整 HTML、不連外、不寫 DB、不建立候選活動、不允許候選導入、不掛 schedulerinvalid JSON 只回診斷錯誤。
- 2026-05-19 追加 manual sample candidate handoff`/api/market_intel/manual_sample_review/candidate_handoff` 將已通過審核的 sample result 轉成只讀候選活動 handoff payload包含 candidate key、平台、來源、URL、信心分級、排序與人工審核狀態。此入口保持 CSRF 保護,不保存 handoff、不建立 review queue、不寫 market_*、不允許候選導入、不掛 scheduler。
- 2026-05-19 追加 manual sample candidate queue draft`services.market_intel.manual_sample_candidate_queue``/api/market_intel/manual_sample_review/candidate_queue_draft` 將 handoff 候選轉成只讀人工審核 queue draft包含 queue item key、review priority、review state 與 approval_required。此入口保持 CSRF 保護,不建立正式 queue、不保存草案、不寫 market_*、不自動核准候選、不掛 scheduler。
- 2026-05-19 追加 manual sample candidate queue approval`/api/market_intel/manual_sample_review/candidate_queue_approval` 將 queue draft 對齊既有 `market_alert_review_queue` 契約,輸出 row preview、必填欄位 gate、寫入 flags、備份與人工批准 gate。此入口保持 CSRF 保護,不建立 approval record、不寫 review queue、不開 DB transaction、不掛 scheduler。
- 2026-05-19 追加 manual sample candidate queue transaction`/api/market_intel/manual_sample_review/candidate_queue_transaction` 將 queue row preview 轉成 idempotent insert statement preview、payload hash、runtime order 與 rollback plan。此入口保持 CSRF 保護,不開 DB connection、不開 transaction、不 commit、不建立 approval record、不寫 `market_alert_review_queue`
- 2026-05-19 追加 candidate queue writer CLI gate`services.market_intel.candidate_queue_writer_cli``scripts/market_intel_candidate_queue_writer.py``/api/market_intel/manual_sample_review/candidate_queue_writer_status` 定義 `MARKET_INTEL_QUEUE_WRITE_APPROVAL` 一次性 token、execute/apply flags、備份、migration smoke 與 rollback gate。此階段只回 writer status不開 DB connection、不啟用實際 writer、不寫 `market_alert_review_queue`、不掛 scheduler。
- 2026-05-19 追加 candidate queue writer preflight`services.market_intel.candidate_queue_writer_preflight``/api/market_intel/manual_sample_review/candidate_queue_writer_preflight` 檢查 transaction preview payload key 到 `market_alert_review_queue` 欄位映射、缺欄與 dedupe unique index。UI 預設 `execute=false` 不連 DBCLI 明確 `--read-only-preflight` 時也只查 catalog不寫 DB、不 commit、不掛 scheduler。
- 2026-05-19 追加 candidate queue writer CLI transaction`scripts/market_intel_candidate_queue_writer.py` 在 CLI-only 情境支援受控 idempotent insert transaction必須同時通過 transaction payload、read-only preflight、`--execute``--apply-real-write`、一次性 approval token、備份確認與 migration live smoke。API/UI 仍不得讀取 approval token、不得開 DB connection、不得寫 `market_alert_review_queue`、不得掛 scheduler部署 smoke 不執行正式 DB 寫入。
- 2026-05-19 追加 candidate queue writer post-write smoke`services.market_intel.candidate_queue_writer_postwrite_smoke``/api/market_intel/manual_sample_review/candidate_queue_writer_postwrite_smoke` 依 transaction preview dedupe key 只讀查詢 `market_alert_review_queue`,供 CLI 真寫入後確認 row 是否落地。UI 預設 `execute=false` 不連 DB人工 smoke 即使 `execute=true` 也只讀查詢,不寫 DB、不 commit、不掛 scheduler。
- 2026-05-19 追加 candidate queue writer operator drill`services.market_intel.candidate_queue_writer_operator_drill``/api/market_intel/manual_sample_review/candidate_queue_writer_operator_drill` 組裝 reviewed sample、備份、read-only preflight、CLI writer、post-write smoke 的操作員順序與 gate。此 drill 只輸出可稽核操作計畫API/UI 不讀 approval token、不執行 CLI、不連 DB、不寫 queue、不 commit、不掛 scheduler。
- 2026-05-19 追加 candidate queue writer run package`services.market_intel.candidate_queue_writer_run_package``/api/market_intel/manual_sample_review/candidate_queue_writer_run_package` 整理正式 CLI 小流量寫入前的 payload manifest、required artifacts、command bundle、operator signoff 與 rollback plan。此 package 只輸出可稽核證據包預覽API/UI 不產檔、不讀 approval token、不執行 CLI、不連 DB、不寫 queue、不 commit、不掛 scheduler。
- 2026-05-19 追加 candidate queue writer run readiness`services.market_intel.candidate_queue_writer_run_readiness``/api/market_intel/manual_sample_review/candidate_queue_writer_run_readiness` 檢查正式 CLI 小流量寫入前的 reviewed sample 路徑、備份路徑、preflight 輸出、migration live smoke、shell-only token acknowledgement 與禁止 token 進 API。此 readiness 只輸出操作員證據缺口API/UI 不產檔、不讀 approval token、不執行 CLI、不連 DB、不寫 queue、不 commit、不掛 scheduler。
- 2026-05-19 追加 candidate queue writer run receipt`services.market_intel.candidate_queue_writer_run_receipt``/api/market_intel/manual_sample_review/candidate_queue_writer_run_receipt` 審核 CLI 小流量寫入後的 writer output、post-write smoke、dedupe key 一致性、artifact 路徑與 token 外洩風險。此 receipt 只輸出安全摘要API/UI 不回吐 receipt 原文、不讀 approval token、不執行 CLI、不連 DB、不寫 queue、不 commit、不掛 scheduler。
- 2026-05-19 追加 candidate queue writer run closeout`services.market_intel.candidate_queue_writer_run_closeout``/api/market_intel/manual_sample_review/candidate_queue_writer_run_closeout` 在 receipt 通過後整理 closeout gate、人工確認與下一階段 promotion 摘要。此 closeout 只允許放行到人工 queue review / read-only inventoryAPI/UI 不回吐原始 receipt、不讀 approval token、不執行 CLI、不連 DB、不寫 queue、不掛 scheduler。
- 2026-05-19 追加 candidate queue review handoff`services.market_intel.candidate_queue_review_handoff``/api/market_intel/manual_sample_review/candidate_queue_review_handoff` 將 closeout 後的 expected dedupe key、review contract、人工操作順序與 forbidden API actions 整理為交接包。此 handoff 不查 DB、不更新 `review_state`、不補寫 missing queue row、不讀 approval token、不掛 scheduler。
- 2026-05-19 追加 candidate queue review inventory`services.market_intel.candidate_queue_review_inventory``/api/market_intel/manual_sample_review/candidate_queue_review_inventory` 將 handoff、post-write smoke 與 live DB inventory 串成只讀人工審核庫存檢查。預設不連 DB人工明確要求只讀查詢時仍不更新 `review_state`、不補寫 queue row、不讀 approval token、不掛 scheduler。
- 2026-05-19 追加 candidate queue review decision`services.market_intel.candidate_queue_review_decision``/api/market_intel/manual_sample_review/candidate_queue_review_decision` 將通過 inventory 的 queue row 整理成人工決策草案,限制 next state 為 `confirmed` / `rejected` / `deferred`。此階段不更新 `review_state`、不寫 decision record、不讀 approval token、不掛 scheduler。
- 2026-05-19 追加 candidate queue review decision approval`services.market_intel.candidate_queue_review_decision_approval``/api/market_intel/manual_sample_review/candidate_queue_review_decision_approval` 檢查人工決策草案是否可進入下一個 CLI-only transaction preview。此階段不更新 `review_state`、不寫 decision record、不建立 approval record、不讀 approval token、不掛 scheduler。
- 2026-05-19 追加 candidate queue review decision transaction`services.market_intel.candidate_queue_review_decision_transaction``/api/market_intel/manual_sample_review/candidate_queue_review_decision_transaction` 將已批准的人工決策整理成 `review_state` update statement preview、payload hash、runtime order 與 rollback plan。此階段不連 DB、不開 transaction、不 commit、不更新 `review_state`、不讀 approval token、不執行 CLI、不掛 scheduler真正更新只允許後續人工 shell/CLI 寫入窗口。
- 2026-05-19 追加 candidate queue review decision writer CLI gate`services.market_intel.candidate_queue_review_decision_writer_cli``scripts/market_intel_review_decision_writer.py``/api/market_intel/manual_sample_review/candidate_queue_review_decision_writer_status` 先建立 review_state writer 的 shell-only gate、一次性 token env var、command bundle 與 rollback plan。此階段 writer implementation 保持 disabledAPI/UI 不讀 approval token、不執行 CLI、不連 DB、不開 transaction、不 commit、不更新 `review_state`、不掛 scheduler。
- 2026-05-19 追加 candidate queue review decision writer preflight`services.market_intel.candidate_queue_review_decision_writer_preflight``/api/market_intel/manual_sample_review/candidate_queue_review_decision_writer_preflight` 檢查 writer status、review_state update payload、狀態轉換與 token 外洩風險。API/UI 即使收到 `execute=true``apply_real_write=true` 也只回 blocked preview不連 DB、不執行 CLI、不更新 `review_state`、不 commit、不讀 approval token、不掛 scheduler。
- 2026-05-19 追加 candidate queue review decision writer post-write smoke`services.market_intel.candidate_queue_review_decision_writer_postwrite_smoke``/api/market_intel/manual_sample_review/candidate_queue_review_decision_writer_postwrite_smoke` 依 review_state transaction preview 的 dedupe key 只讀查詢 `market_alert_review_queue`,確認人工 CLI 更新後的 `review_state` 是否符合預期。UI 預設 `execute=false` 不連 DB人工 smoke 即使 `execute=true` 也只讀查詢,不更新 `review_state`、不 commit、不讀 approval token、不掛 scheduler。
- 2026-05-19 追加 candidate queue review decision writer operator drill`services.market_intel.candidate_queue_review_decision_writer_operator_drill``/api/market_intel/manual_sample_review/candidate_queue_review_decision_writer_operator_drill` 整理 review_state CLI 更新前後的操作員順序、preflight、post-write smoke、gate 與 rollback plan。此 drill 只輸出可稽核操作計畫API/UI 不讀 approval token、不執行 CLI、不連 DB、不更新 `review_state`、不 commit、不掛 scheduler。
- 2026-05-19 追加 candidate queue review decision writer run package`services.market_intel.candidate_queue_review_decision_writer_run_package``/api/market_intel/manual_sample_review/candidate_queue_review_decision_writer_run_package` 將 review_state transaction、preflight、operator drill、writer gate、post-write smoke、必要 artifact 與 rollback plan 組成正式 CLI 更新前的可稽核 package。此 package 只輸出預覽API/UI 不寫檔、不讀 approval token、不執行 CLI、不連 DB、不更新 `review_state`、不 commit、不掛 scheduler。
- 2026-05-19 追加 candidate queue review decision writer run readiness`services.market_intel.candidate_queue_review_decision_writer_run_readiness``/api/market_intel/manual_sample_review/candidate_queue_review_decision_writer_run_readiness` 檢查 review_state CLI 更新前的 transaction JSON、備份、preflight、shell-only token 與 post-write smoke 計畫是否齊備。此 readiness 只輸出操作員 gate 預覽API/UI 不寫檔、不讀 approval token、不執行 CLI、不連 DB、不更新 `review_state`、不 commit、不掛 scheduler。
- 2026-05-19 追加 candidate queue review decision writer run receipt`services.market_intel.candidate_queue_review_decision_writer_run_receipt``/api/market_intel/manual_sample_review/candidate_queue_review_decision_writer_run_receipt` 審核 review_state CLI 更新後的 writer output、post-write smoke、dedupe key 一致性、artifact 路徑與 token 外洩風險。此 receipt 只輸出安全摘要API/UI 不回吐 receipt 原文、不讀 approval token、不執行 CLI、不連 DB、不更新 `review_state`、不 commit、不掛 scheduler。
- 2026-05-19 追加 candidate queue review decision writer run closeout`services.market_intel.candidate_queue_review_decision_writer_run_closeout``/api/market_intel/manual_sample_review/candidate_queue_review_decision_writer_run_closeout` 在 review_state receipt 通過後整理 closeout gate、操作員 closeout artifact、post-closeout read-only inventory 確認與 promotion 摘要。此 closeout 只允許放行到後續人工/只讀檢查API/UI 不回吐 receipt 原文、不讀 approval token、不執行 CLI、不連 DB、不更新 `review_state`、不 commit、不掛 scheduler。
- 2026-05-19 追加 candidate queue review decision post-closeout inventory`services.market_intel.candidate_queue_review_decision_post_closeout_inventory``routes.market_intel_review_post_routes``/api/market_intel/manual_sample_review/candidate_queue_review_decision_post_closeout_inventory` 在 review_state closeout 後整理 post-write smoke、live inventory、dedupe key 與 review_state 結果。此 inventory 只允許只讀驗證API/UI 不讀 approval token、不執行 CLI、不更新 `review_state`、不寫 DB、不 commit、不掛 scheduler。
- 2026-05-19 追加 candidate queue review completion archive`services.market_intel.candidate_queue_review_completion_archive``/api/market_intel/manual_sample_review/candidate_queue_review_completion_archive` 在 post-closeout inventory 後整理 receipt、closeout、inventory、dedupe key、review_state row snapshot 與 artifact path manifest。此 archive gate 只輸出封存預覽API/UI 不寫檔、不讀 approval token、不執行 CLI、不更新 `review_state`、不寫 DB、不 commit、不掛 scheduler。
- 2026-05-19 追加 candidate queue review archive summary`services.market_intel.candidate_queue_review_archive_summary``/api/market_intel/manual_sample_review/candidate_queue_review_archive_summary` 在 review completion archive 後整理可供摘要/報表審核的結構化輸入。此 summary gate 不產生 AI 摘要API/UI 不呼叫 LLM、不派送 Telegram、不寫檔、不讀 approval token、不執行 CLI、不更新 `review_state`、不寫 DB、不 commit、不掛 scheduler。
- 2026-05-19 追加 candidate queue review AI summary preflight`services.market_intel.candidate_queue_review_ai_summary_preflight``/api/market_intel/manual_sample_review/candidate_queue_review_ai_summary_preflight` 在 archive summary 後檢查未來 AI 摘要前置條件、Ollama-first 三主機級聯與 Gemini 備援邊界。此 preflight 不產生 AI 摘要API/UI 不呼叫 LLM、不派送 Telegram、不寫檔、不讀 approval token、不執行 CLI、不更新 `review_state`、不寫 DB、不 commit、不掛 scheduler188 不可作為 Ollama 節點。
- 2026-05-19 追加 candidate queue review AI summary run package`services.market_intel.candidate_queue_review_ai_summary_run_package``/api/market_intel/manual_sample_review/candidate_queue_review_ai_summary_run_package` 在 AI summary preflight 後整理手動 Ollama 摘要任務包、prompt contract、輸出 schema 與 artifact path contract。此 package gate 不產生 AI 摘要API/UI 不呼叫 LLM、不派送 Telegram、不寫檔、不讀 approval token、不執行 CLI、不更新 `review_state`、不寫 DB、不 commit、不掛 schedulerGemini 僅能作為 Ollama cascade 全失敗後的備援。
- 2026-05-19 追加 candidate queue review AI summary output receipt`services.market_intel.candidate_queue_review_ai_summary_output_receipt``/api/market_intel/manual_sample_review/candidate_queue_review_ai_summary_output_receipt` 在 run package 後驗收人工 Ollama 摘要輸出的 schema、`evidence_refs``model_route`。此 receipt gate 不產生 AI 摘要API/UI 不呼叫 LLM、不派送 Telegram、不寫檔、不讀 approval token、不執行 CLI、不更新 `review_state`、不寫 DB、不 commit、不掛 scheduler摘要持久化與 Telegram 派送必須另開後續 gate。
- 2026-05-19 追加 candidate queue review AI summary persistence preflight`services.market_intel.candidate_queue_review_ai_summary_persistence_preflight``/api/market_intel/manual_sample_review/candidate_queue_review_ai_summary_persistence_preflight` 在 output receipt 後整理未來 CLI-only `market_alert_review_queue.metadata_json.ai_summary_review` persistence contract、payload hash 與 metadata patch preview。此 preflight 不產生 transaction、不寫 summary record、不寫 `metadata_json`、不呼叫 LLM、不派送 Telegram、不讀 approval token、不執行 CLI、不更新 `review_state`、不寫 DB、不 commit、不掛 scheduler真正持久化與 Telegram dispatch 必須另開後續 gate。
- 2026-05-19 追加 candidate queue review AI summary persistence transaction`services.market_intel.candidate_queue_review_ai_summary_persistence_transaction``/api/market_intel/manual_sample_review/candidate_queue_review_ai_summary_persistence_transaction` 在 persistence preflight 後產生未來 CLI-only `metadata_json` UPDATE statement preview、parameter preview 與 rollback plan。此 transaction gate 不開 DB、不執行 SQL、不寫 transaction、不寫 summary record、不寫 `metadata_json`、不讀 approval token、不執行 CLI、不更新 `review_state`、不派送 Telegram、不呼叫 LLM、不 commit、不掛 scheduler真正寫入必須另開 CLI writer gate 與 post-write smoke。
- 2026-05-19 追加 candidate queue review AI summary persistence writer preflight`services.market_intel.candidate_queue_review_ai_summary_persistence_writer_preflight``/api/market_intel/manual_sample_review/candidate_queue_review_ai_summary_persistence_writer_preflight` 在 transaction preview 後檢查 CLI-only writer contract、`metadata_json` backup requirement、post-write smoke requirement 與 artifact path gate。此 writer preflight 不開 DB、不執行 SQL、不寫 preflight、不寫 summary record、不寫 `metadata_json`、不讀 approval token、不執行 CLI、不更新 `review_state`、不派送 Telegram、不呼叫 LLM、不 commit、不掛 scheduler真正寫入必須另開 CLI run package、operator readiness、receipt 與 post-write smoke。
- 2026-05-19 追加 candidate queue review AI summary persistence run package`services.market_intel.candidate_queue_review_ai_summary_persistence_run_package``/api/market_intel/manual_sample_review/candidate_queue_review_ai_summary_persistence_run_package` 在 writer preflight 後整理 payload manifest、CLI command bundle、required artifacts、operator signoff 與 rollback plan。此 run package 不開 DB、不執行 SQL、不寫 run package、不寫 summary record、不寫 `metadata_json`、不讀 approval token、不執行 CLI、不更新 `review_state`、不派送 Telegram、不呼叫 LLM、不 commit、不掛 scheduler真正寫入必須另開 operator readiness、CLI receipt、post-write smoke 與 closeout。
- 2026-05-20 追加 candidate queue review AI summary persistence run readiness`services.market_intel.candidate_queue_review_ai_summary_persistence_run_readiness``/api/market_intel/manual_sample_review/candidate_queue_review_ai_summary_persistence_run_readiness` 在 run package 後檢查操作員 artifact path、metadata_json backup、read-only preflight、shell-only token acknowledgement 與 post-write smoke 計畫。此 readiness 不開 DB、不執行 SQL、不寫 readiness artifact、不寫 summary record、不寫 `metadata_json`、不讀 approval token、不執行 CLI、不更新 `review_state`、不派送 Telegram、不呼叫 LLM、不 commit、不掛 scheduler真正寫入必須由後續人工 CLI 與 receipt/post-write smoke gate 驗收。
- 2026-05-20 追加 candidate queue review AI summary persistence run receipt`services.market_intel.candidate_queue_review_ai_summary_persistence_run_receipt``/api/market_intel/manual_sample_review/candidate_queue_review_ai_summary_persistence_run_receipt` 審核 metadata_json CLI 寫入後的 writer output、post-write smoke、dedupe key、summary payload hash、artifact path 與 token 外洩風險。此 receipt 只輸出安全摘要API/UI 不回吐 receipt 原文、不讀 approval token、不執行 CLI、不開 DB、不寫 `metadata_json`、不更新 `review_state`、不派送 Telegram、不 commit、不掛 scheduler。
- 2026-05-20 追加 candidate queue review AI summary persistence run closeout`services.market_intel.candidate_queue_review_ai_summary_persistence_run_closeout``/api/market_intel/manual_sample_review/candidate_queue_review_ai_summary_persistence_run_closeout` 在 receipt 通過後整理 closeout gate、操作員 closeout artifact、Telegram dispatch separate-gate 確認與 promotion 摘要。此 closeout 只允許放行到後續 Telegram dispatch gateAPI/UI 不回吐 receipt 原文、不讀 approval token、不執行 CLI、不開 DB、不寫 `metadata_json`、不更新 `review_state`、不派送 Telegram、不呼叫 LLM、不 commit、不掛 scheduler。
- 2026-05-20 追加 candidate queue review AI summary persistence Telegram dispatch gate`services.market_intel.candidate_queue_review_ai_summary_persistence_telegram_dispatch_gate``/api/market_intel/manual_sample_review/candidate_queue_review_ai_summary_persistence_telegram_dispatch_gate` 在 closeout 後整理 Telegram message contract、channel label、artifact path、token 外洩檢查與下一階段 run package promotion。此 gate 只允許放行到後續 Telegram dispatch run packageAPI/UI 不讀 approval/Telegram token、不呼叫 LLM、不開 DB、不寫檔、不派送 Telegram、不更新 `review_state`、不 commit、不掛 scheduler。
- 2026-05-20 追加 candidate queue review AI summary persistence Telegram dispatch run package`services.market_intel.candidate_queue_review_ai_summary_persistence_telegram_dispatch_run_package``/api/market_intel/manual_sample_review/candidate_queue_review_ai_summary_persistence_telegram_dispatch_run_package` 在 dispatch gate 後整理 message contract snapshot、command plan、artifact checklist 與下一階段 readiness promotion。此 run package 只允許放行到後續 Telegram dispatch run readinessAPI/UI 不讀 approval/Telegram token、不呼叫 LLM、不開 DB、不寫檔、不派送 Telegram、不更新 `review_state`、不 commit、不掛 scheduler。
- 2026-05-20 追加 candidate queue review AI summary persistence Telegram dispatch run readiness`services.market_intel.candidate_queue_review_ai_summary_persistence_telegram_dispatch_run_readiness``/api/market_intel/manual_sample_review/candidate_queue_review_ai_summary_persistence_telegram_dispatch_run_readiness` 在 dispatch run package 後檢查 message preview、run package、dispatch receipt artifact path、manual command review、Telegram token shell-only 與 no-side-effect 確認。此 readiness 只允許放行到人工 Telegram dispatch 後的 receipt reviewAPI/UI 不讀 approval/Telegram token、不呼叫 LLM、不開 DB、不寫檔、不派送 Telegram、不更新 `review_state`、不 commit、不掛 scheduler。
- 2026-05-20 追加 candidate queue review AI summary persistence Telegram dispatch run receipt`services.market_intel.candidate_queue_review_ai_summary_persistence_telegram_dispatch_run_receipt``/api/market_intel/manual_sample_review/candidate_queue_review_ai_summary_persistence_telegram_dispatch_run_receipt` 審核人工 Telegram 派送後貼回的 message id、channel、summary hash、receipt artifact 與 token 外洩風險。此 receipt 只允許放行到後續 Telegram dispatch closeoutAPI/UI 不讀 approval/Telegram token、不呼叫 LLM、不補發或重送 Telegram、不開 DB、不寫檔、不更新 `review_state`、不 commit、不掛 scheduler。
- 2026-05-20 追加 candidate queue review AI summary persistence Telegram dispatch closeout`services.market_intel.candidate_queue_review_ai_summary_persistence_telegram_dispatch_closeout``/api/market_intel/manual_sample_review/candidate_queue_review_ai_summary_persistence_telegram_dispatch_closeout` 在人工 Telegram receipt 通過後整理 closeout artifact、receipt archive、message visibility、duplicate dispatch 與 post-closeout monitoring gate。此 closeout 只允許放行到後續封存/報表 gateAPI/UI 不讀 approval/Telegram token、不呼叫 LLM、不補發或重送 Telegram、不開 DB、不寫檔、不更新 `review_state`、不 commit、不掛 scheduler。
- 2026-05-20 追加 candidate queue review AI summary persistence Telegram dispatch archive`services.market_intel.candidate_queue_review_ai_summary_persistence_telegram_dispatch_archive``/api/market_intel/manual_sample_review/candidate_queue_review_ai_summary_persistence_telegram_dispatch_archive` 在 closeout 通過後整理 message id、channel、summary hash、receipt/closeout/message preview/archive artifact path 與 duplicate/monitoring audit manifest。此 archive 只輸出封存預覽並放行到後續 archive summary / 報表輸入 gateAPI/UI 不讀 approval/Telegram token、不呼叫 LLM、不補發或重送 Telegram、不開 DB、不寫檔、不更新 `review_state`、不 commit、不掛 scheduler。
- 2026-05-20 追加 candidate queue review AI summary persistence Telegram dispatch archive summary`services.market_intel.candidate_queue_review_ai_summary_persistence_telegram_dispatch_archive_summary``/api/market_intel/manual_sample_review/candidate_queue_review_ai_summary_persistence_telegram_dispatch_archive_summary` 在 archive 通過後整理 message identity、dispatch audit、artifact manifest 與後續 report input 所需 sections。此 archive summary 只準備報表/summary inputAPI/UI 不讀 approval/Telegram token、不呼叫 LLM、不補發或重送 Telegram、不開 DB、不寫檔、不更新 `review_state`、不 commit、不掛 scheduler後續報表輸入必須另開 gate。
- 2026-05-20 追加 candidate queue review AI summary persistence Telegram dispatch report input`services.market_intel.candidate_queue_review_ai_summary_persistence_telegram_dispatch_report_input``routes.market_intel_review_report_routes``/api/market_intel/manual_sample_review/candidate_queue_review_ai_summary_persistence_telegram_dispatch_report_input` 在 archive summary 通過後整理 report input sections、report contract、message evidence 與 dispatch audit traceability。此 report input 只準備後續報表 run packageAPI/UI 不讀 approval/Telegram token、不呼叫 LLM、不補發或重送 Telegram、不開 DB、不寫檔、不產報表、不更新 `review_state`、不 commit、不掛 scheduler真正報表產製必須另開 gate。
- 2026-05-20 追加 candidate queue review AI summary persistence Telegram dispatch report run package`services.market_intel.candidate_queue_review_ai_summary_persistence_telegram_dispatch_report_run_package``routes.market_intel_review_report_routes``/api/market_intel/manual_sample_review/candidate_queue_review_ai_summary_persistence_telegram_dispatch_report_run_package` 在 report input 通過後整理 run package contract、evidence refs、package sections 與後續 report run readiness gate。此 run package 只準備報表執行審核包API/UI 不讀 approval/Telegram token、不呼叫 LLM、不補發或重送 Telegram、不開 DB、不寫檔、不產報表、不更新 `review_state`、不 commit、不掛 scheduler真正報表產製必須另開 readiness gate。
- 2026-05-20 追加 candidate queue review AI summary persistence Telegram dispatch report run readiness`services.market_intel.candidate_queue_review_ai_summary_persistence_telegram_dispatch_report_run_readiness``routes.market_intel_review_report_routes``/api/market_intel/manual_sample_review/candidate_queue_review_ai_summary_persistence_telegram_dispatch_report_run_readiness` 在 report run package 通過後整理 report generation readiness manifest、manual report command boundary、artifact path gate 與後續 report run receipt gate。此 run readiness 只檢查可否進入後續人工/獨立 job 報表產製API/UI 不讀 approval/Telegram token、不呼叫 LLM、不補發或重送 Telegram、不開 DB、不寫檔、不產報表、不更新 `review_state`、不 commit、不掛 scheduler真正產出結果必須另開 receipt gate。
- 2026-05-20 追加 candidate queue review AI summary persistence Telegram dispatch report run receipt`services.market_intel.candidate_queue_review_ai_summary_persistence_telegram_dispatch_report_run_receipt``routes.market_intel_review_report_routes``/api/market_intel/manual_sample_review/candidate_queue_review_ai_summary_persistence_telegram_dispatch_report_run_receipt` 在 report run readiness 通過後審核人工/獨立 job 產出的 report receipt、report artifact path/hash、必要章節、summary hash 與 runtime boundary。此 receipt 只允許放行到後續 market intel report closeoutAPI/UI 不讀 approval/Telegram token、不呼叫 LLM、不補產報表、不補發或重送 Telegram、不開 DB、不寫檔、不更新 `review_state`、不 commit、不掛 scheduler。
- 2026-05-20 追加 candidate queue review AI summary persistence Telegram dispatch report closeout`services.market_intel.candidate_queue_review_ai_summary_persistence_telegram_dispatch_report_closeout``routes.market_intel_review_report_routes``/api/market_intel/manual_sample_review/candidate_queue_review_ai_summary_persistence_telegram_dispatch_report_closeout` 在 report run receipt 通過後審核 closeout artifact、receipt/report artifact path、hash 與章節覆核、archive separate gate 與 runtime boundary。此 closeout 只允許放行到後續 market intel report archiveAPI/UI 不讀 approval/Telegram token、不呼叫 LLM、不補產報表、不補發或重送 Telegram、不開 DB、不寫檔、不更新 `review_state`、不 commit、不掛 scheduler後續 report archive 必須另開 gate。
- 2026-05-20 追加 candidate queue review AI summary persistence Telegram dispatch report archive`services.market_intel.candidate_queue_review_ai_summary_persistence_telegram_dispatch_report_archive``routes.market_intel_review_report_routes``/api/market_intel/manual_sample_review/candidate_queue_review_ai_summary_persistence_telegram_dispatch_report_archive` 在 report closeout 通過後審核 archive/closeout/receipt/report output artifact path、hash 與章節、archive manifest、retention policy 與後續 archive summary separate gate。此 archive 只允許放行到後續 market intel report archive summaryAPI/UI 不讀 approval/Telegram token、不呼叫 LLM、不補產報表、不補發或重送 Telegram、不開 DB、不寫檔、不更新 `review_state`、不 commit、不掛 scheduler後續 archive summary 必須另開 gate。
- 2026-05-20 追加 candidate queue review AI summary persistence Telegram dispatch report archive summary`services.market_intel.candidate_queue_review_ai_summary_persistence_telegram_dispatch_report_archive_summary``routes.market_intel_review_report_routes``/api/market_intel/manual_sample_review/candidate_queue_review_ai_summary_persistence_telegram_dispatch_report_archive_summary` 在 report archive 通過後整理 report identity、archive traceability、integrity review 與 runtime safety sections僅放行到後續 report catalog handoff gateAPI/UI 不讀 approval/Telegram token、不呼叫 LLM、不補產報表、不補發或重送 Telegram、不開 DB、不寫檔、不更新 `review_state`、不 commit、不掛 scheduler後續 catalog handoff 必須另開 gate。
- 2026-05-20 追加 candidate queue review AI summary persistence Telegram dispatch report catalog handoff`services.market_intel.candidate_queue_review_ai_summary_persistence_telegram_dispatch_report_catalog_handoff``routes.market_intel_review_report_routes``/api/market_intel/manual_sample_review/candidate_queue_review_ai_summary_persistence_telegram_dispatch_report_catalog_handoff` 在 report archive summary 通過後整理 catalog identity、artifact manifest、section keys 與 hash traceability僅放行到後續 report catalog index gateAPI/UI 不讀 approval/Telegram token、不呼叫 LLM、不補產報表、不補發或重送 Telegram、不開 DB、不寫 catalog record、不更新 `review_state`、不 commit、不掛 scheduler後續 catalog index / write preflight 必須另開 gate。
### Phase 4Coupang / Shopee Adapter
- Coupang 先做保守 adapter初始版本只註冊官方公開入口。
- Shopee 因動態資料與反爬風險較高,初始版本只註冊公開入口並維持更嚴格節流。
### Phase 5Product Matching + HITL
- 用品牌、規格、容量、關鍵字與現有商品資料計算 match score。
- 低信心進人工審核,不自動合併。
### Phase 6AI Insight / Telegram
- 只基於 DB 實證資料產生摘要與告警。
- 不做空泛 LLM 建議。
- 高風險告警需包含平台、活動、商品、價差、資料時間與可追溯 run id。
## Alternatives Considered
### 方案 A直接擴充 `promo_products`
不採用。`promo_products` 偏 MOMO 活動商品語境,無法乾淨承載跨平台活動、商品快照、價格歷史、比對審核與 crawler run log。
### 方案 B直接塞進 `scheduler.py` 與既有 crawler service
不採用。`scheduler.py` 與多個 crawler service 已達大檔治理門檻,新增跨平台 adapter 會讓排程與錯誤隔離更脆弱。
### 方案 C先做完整 UI 再補資料
不採用。違反真實資料與真實頁面規範,容易產生假 KPI、假商品與不可診斷狀態。
## Consequences
**正面**
- 市場情報可以獨立演進不污染業績分析、dashboard、scheduler 既有技術債。
- 每平台 adapter 可單獨停用、測試與回退。
- `market_*` schema 可保留歷史、做趨勢與商品比對。
- AI 告警能基於可追溯 DB run log降低空泛推論。
**負面**
- 初期開發量比「直接塞舊表」更高。
- 需要新增 schema、service、route、UI 與 scheduler registry。
- Shopee 等平台可能因公開資料穩定性與 rate limit 需要較長探索期。
## Acceptance Criteria
- Phase 0 完成後,不改 runtime 行為。
- Phase 1 完成後,`MARKET_INTEL_ENABLED=false` 時所有新功能完全不影響既有頁面與排程。
- 任一 crawler adapter 失敗不得阻塞既有 MOMO 排程。
- 新市場情報 route 不新增到 `app.py`
- 任一新 Python 檔若超過 600 行需提出拆分理由,超過 800 行需更新模組化 inventory。

View File

@@ -0,0 +1,50 @@
# ADR-036: FastAPI Strangler Migration不作為前端 V3 前置條件
Status: Accepted
Date: 2026-05-12
## Context
前端 V3 視覺包已進入落地評估,同時出現「既然前端要一次到位,後端也應同步從 Flask 改為 FastAPI」的建議。
現有系統的重資產集中在 Python爬蟲、AI 學習鏈、Telegram bot、APScheduler、SQLAlchemy models、pgvector、AutoHeal 與多個 service 模組。FastAPI 若被定位為 HTTP layer 轉換,理論上可沿用大部分 Python 業務邏輯;但目前 `app.py``routes/` 與 Jinja 頁面仍承接大量 HTTP glue、template context、CSRF/session、錯誤處理與部分業務邏輯。
同時,前端 V3 包內部分頁面仍有正式資料接線風險:若只為了視覺更新直接替換,就可能移除現有 PChome 比價、AI 挑品、歷史價格、AI 觀測台等真實功能,違反 CONSTITUTION 第 14.1 條。
## Decision
FastAPI 是可接受的中期目標,但不得作為前端 V3 落地的前置條件,也不得與前端視覺更新綁成同一個大爆炸工程。
採用以下順序:
1. 前端 V3 先在現有 Flask runtime 內落地,僅替換已確認接上真實資料、既有 route/API 與行為不退化的頁面。
2. 對於會移除現有功能的 V3 prototype 頁,先拒絕替換,保留現行正式頁。
3. 後端重構優先做 HTTP-agnostic service extraction把 route 內資料組裝、查詢、匯出、狀態診斷逐步搬到 `services/`,讓 Flask route 變薄。
4. FastAPI 僅能以 strangler pattern 漸進引入:新 API 或已抽乾的 API 可掛在新 app經 OpenAPI contract、測試與 Nginx path split 驗證後再切流。
5. 不採用 Node 重寫後端。Next.js 前端若需要型別,未來由 OpenAPI 產生 client/types不以「前後端同語言」作為重寫理由。
## Alternatives Considered
### A. 前端 V3 與 FastAPI Phase 1 同時執行
拒絕。這會同時改動 template/rendering、API boundary、auth/session、CSRF、Nginx、Docker、health check 與 deploy rollback。對目前生產系統而言風險面過大也會把原本可獨立驗收的 UI 工作變成跨層遷移。
### B. 維持 Flask 永久不動
拒絕作為長期結論。Flask 可繼續承接現有 Jinja/route但 OpenAPI、型別 client、async API 與新前端資料邊界確實更適合用 FastAPI 承接。問題不是是否能換,而是何時、以什麼切面換。
### C. Node/Next API 重寫
拒絕。核心業務與自動化資產都在 Python改 Node 等同重寫爬蟲、AI、排程、Telegram 與資料層,收益不足以抵銷風險。
## Consequences
- 前端 V3 可以立即繼續落地,但每頁必須通過真實資料與行為不退化檢查。
- FastAPI migration 的第一步不是開新框架,而是清 route、補 contract、抽 services。
- 若未來建立 `momo-fastapi` service必須先有
- endpoint inventory 與 owner mapping
- auth/session/CSRF 或 token strategy
- OpenAPI contract test
- `/health`、production smoke、rollback plan
- Nginx path split 只切已驗證 path。
- Flask、Jinja 與 `templates/` 的刪除只能在所有對應頁面完成遷移並通過 smoke 後進行。

View File

@@ -0,0 +1,45 @@
# ADR-037: Webcrumbs 共用 UI Runtime 接入
Status: Accepted
Date: 2026-05-31
## Context
momo-pro 的前端已進入 V2/V3 視覺治理階段,後續會需要更穩定的跨頁 UI 元件、microfrontend/plugin loader 與跨專案視覺實驗入口。Webcrumbs 可作為共用 UI runtime但若各專案各自引用官方 CDN、使用 `@latest`,或把上游 repo 整包放進 momo-pro會造成供應鏈、版本漂移、授權與生產可控性風險。
本專案目前仍以 Flask/Jinja 為正式 runtime不能因導入外部 UI runtime 而繞過既有登入、CSRF、health check、部署與真實資料不退化紅線。
## Decision
Webcrumbs 在 momo-pro 中只作為「自架、固定版本、可診斷」的共用 UI runtime/plugin loader不作為主前端框架替代品。
採用以下規則:
1. runtime 由 `WEBCRUMBS_*` 環境變數設定,正式頁面預設指向 momo-pro 同源 `/webcrumbs-assets/loader/webcrumbs-compatible-loader.js`
2. `/webcrumbs-assets/` 只代理 allowlist prefix`loader/``plugins/``demo/`,上游預設為 188 user-space Shared UI Hub `http://192.168.0.188:18088`
3. `ewoooc_base.html` 只在 `WEBCRUMBS_ENABLED=true` 且 runtime URL 通過 http(s) 或同源絕對路徑檢查時輸出 script。
4. 新增 `/webcrumbs` 診斷入口,顯示 runtime URL、版本、plugin base 與 asset upstream 狀態。
5. Webcrumbs plugin 必須使用自架且版本化 URI例如 `/webcrumbs-assets/plugins/<namespace>/<version>/`
6. 禁止在生產使用官方 `@latest``app.webcrumbs.ai` 或未固定版本的官方 CDN。
7. 不把 Webcrumbs 上游 repo 整包納入 momo-pro 主服務;若修改 runtime 本體,需另外處理 AGPL-3.0 授權義務。
## Alternatives Considered
### A. 每個頁面自行引用官方 Webcrumbs CDN
拒絕。版本不可控,且容易讓正式頁面受外部服務可用性與上游 breaking change 影響。
### B. 把 Webcrumbs repo vendoring 到 momo-pro
拒絕。這會增加主服務體積、授權治理與升級成本,也會讓 UI runtime 與業務後端部署生命週期綁死。
### C. 暫不接任何 runtime只保留純 Jinja/CSS
保留作為 fallback但不足以支援後續跨專案 microfrontend/plugin 化需求。導入 Webcrumbs 時仍維持現有 Jinja 頁面為主,不強制改寫。
## Consequences
- momo-pro 可在不替換 Flask/Jinja 的前提下,逐步嵌入自架 UI plugin。
- 生產部署需同步管理 `WEBCRUMBS_*` 變數與 Shared UI Hub asset upstream。
- 後續任何 Webcrumbs plugin 上線前仍需通過真實資料、權限、RWD、效能與 fallback 檢查。
- 若 runtime URL 無效,系統只會跳過 script 載入並在 config warning / `/webcrumbs` 顯示狀態,不應阻斷主站。

View File

@@ -41,6 +41,24 @@
| [017](ADR-017-modularization-cleanup-roadmap.md) | 模組化收尾路線圖Phase 3f | Accepted | 2026-04-29 |
| [018](ADR-018-four-agent-ai-automation-control-plane.md) | 四 AI Agent 自動化控制面Hermes/NemoTron/OpenClaw/ElephantAlpha | Accepted | 2026-04-29 |
| [019](ADR-019-telegram-bot-agentic-conversation-layer.md) | Telegram Bot Agentic Conversation Layer菜單→Agent 決策統一入口) | Accepted | 2026-05-02 |
| [020](ADR-020-code-review-full-autoheal.md) | Code Review 全自動修復政策(局部覆寫 ADR-012 HITL | Accepted | 2026-05-02 |
| [021](ADR-021-ea-hitl-prefetch-and-alert-impact.md) | EA HITL Pre-fetch + 競價告警必填金額影響量化 | Accepted | 2026-05-03 |
| [022](ADR-022-ppt-system-v3-redesign.md) | PPT v3 — 暖紙風 + matplotlib 專業圖表 + 模板版本快取 | Accepted | 2026-05-02/03 |
| [023](ADR-023-ppt-system-expansion-wave1.md) | PPT 系統 Wave 1 擴展 — 廠商 / 期間回顧 / 品類深度 / 客戶分析8 種新報表) | Accepted | 2026-05-03 |
| [024](ADR-024-ppt-system-wave2-forecast-and-deprecations.md) | PPT 系統 Wave 2 — 檔期前瞻 / 多活動比較 + bcg/growth 廢除 | Accepted | 2026-05-03 |
| [025](ADR-025-ppt-system-wave3-new-product-and-market-intel.md) | PPT 系統 Wave 3 — 新品 30 天追蹤 + 市場情報週報 | Accepted | 2026-05-03 |
| [026](ADR-026-ppt-system-price-elasticity-and-final-roadmap.md) | PPT 系統 — 價格彈性報告 + 完整戰役收尾路線圖 | Accepted | 2026-05-03 |
| [027](ADR-027-primary-ollama-on-gcp.md) | Primary Ollama 遷移至 GCP 高效能主機v5.0 戰役後追加附錄:三主機架構 / 4 fallback 鏈 / 廢止 188 Ollama | Accepted | 2026-05-03 |
| [028](ADR-028-llm-routing-unified-principles.md) | LLM 路由統一準則 — Ollama-First 五大支柱(補述 ADR-027 | Accepted | 2026-05-03 |
| [029](ADR-029-hermes-first-twin-tower.md) | Hermes-First 雙塔分工(戰術主塔 / 戰略副塔Gemini 月支出 -23% | Accepted | 2026-05-03 |
| [030](ADR-030-frontier-multi-vendor-strategy.md) | Frontier 多供應商策略Anthropic + Google + OpenRouterPhase 7 Code Review 升 Claude Opus 4.7 | Accepted | 2026-05-03 |
| [031](ADR-031-mcp-self-hosted-stack.md) | MCP 自建 Stackpostgres + omnisearch + firecrawl + filesystem含 Owen 護欄 #2 Firecrawl 2g 限制) | Accepted | 2026-05-04 |
| [032](ADR-032-rag-autonomous-learning-loop.md) | RAG 自主學習迴圈 — Distiller + PromotionGate + 反饋環Phase 11 | Accepted | 2026-05-03 |
| [033](ADR-033-rag-three-guardrails.md) | RAG 治理三護欄 — Promotion Gate / Firecrawl 資源 / BGE-M3 一致性Owen v5.0 鐵律) | Accepted | 2026-05-03 |
| [034](ADR-034-dynamic-model-router.md) | Caller × Context 動態 Model Router短文 gemma3 / 複雜 SKU qwen3:14b / 重構 coder:32b | Accepted | 2026-05-04 |
| [035](ADR-035-cross-platform-market-campaign-intelligence.md) | 跨平台市場活動情報系統 | Accepted | 2026-05-06 |
| [036](ADR-036-fastapi-strangler-not-frontend-prerequisite.md) | FastAPI Strangler Migration不作為前端 V3 前置條件 | Accepted | 2026-05-12 |
| [037](ADR-037-webcrumbs-shared-ui-runtime.md) | Webcrumbs 共用 UI Runtime 接入 | Accepted | 2026-05-31 |
## 規範

View File

@@ -0,0 +1,53 @@
# Browse.sh Crawler Playbook
> Scope: MOMO / PChome 動態頁診斷、selector 探勘、XHR/network trace。正式價格資料仍以既有 Python crawler、PChome API 與資料庫閉環為準。
## 評估結論
- `browse.sh` 是 Browserbase 提供的 browser CLI主打 open web catalog、browser primitives、debugging、cloud sessions 與 network/console tail。
- 官方安裝入口為 `npm install -g browse`CLI 名稱是 `browse`
- 對本專案最有價值的地方不是取代爬蟲,而是當 MOMO/PChome HTML 或前端 XHR 改版時,快速看 selector、console、network 與可重放 skill。
- 本機目前 Node 16 因 `icu4c` 動態庫缺失無法啟動,不能在本機直接安裝或執行 `browse`。導入方式先採 optional wrapper不影響 production scheduler。
## 使用邊界
- 只允許做 read-only 診斷,不登入、不下單、不加入購物車、不寫第三方狀態。
- 不把 `browse` 放進排程主路徑;若未來要排程化,需另開 ADR 與 feature flag。
- 不把 `browse` 輸出直接寫成正式價格;所有正式比價仍需經 `services/pchome_crawler.py``services/momo_crawler.py``services/marketplace_product_matcher.py``competitor_match_attempts` 診斷。
- Cloud sessions 可能需要 Browserbase 帳號與憑證;憑證不可寫入 repo。
## 本地檢查
```bash
python scripts/tools/browse_sh_probe.py
```
可用時會輸出 `available=true` 與版本;不可用時會輸出原因。若 `browse` 不在 PATH可用
```bash
BROWSE_SH_CLI=/path/to/browse python scripts/tools/browse_sh_probe.py
```
## 診斷流程
1. 先用既有 crawler/API 重現問題,保存失敗 SKU、搜尋詞、候選網址與 matcher diagnostics。
2. 使用 `browse` 開同一頁,查看搜尋結果 DOM、network 與 console。
3. 若找到穩定 XHR/API優先回補到 Python crawler若只能走 DOM才更新 selector。
4. 新增或更新單元測試,至少覆蓋搜尋詞、候選解析與 matcher hard veto。
5. 只在測試通過後部署 app/scheduler/bot不得重建或重啟 `momo-db`
## 常用命令
```bash
python scripts/tools/browse_sh_probe.py -- --version
python scripts/tools/browse_sh_probe.py -- skills list
python scripts/tools/browse_sh_probe.py -- open "https://24h.pchome.com.tw/"
python scripts/tools/browse_sh_probe.py -- network --tail
python scripts/tools/browse_sh_probe.py -- screenshot
```
## MOMO/PChome 導入策略
- PChome目前已有搜尋 API 與商品 API`browse` 只用於確認 API 參數、分頁行為、前端是否切新 endpoint。
- MOMO若既有 BeautifulSoup selector 失效,先用 `browse` 找出前端實際 XHR找到 API 時優先改成 structured API parser。
- Matcher`browse` 只提供候選證據;是否為同款仍由 `marketplace_product_matcher.score_marketplace_match()` 決定。

View File

@@ -0,0 +1,581 @@
# EwoooC × MOMO Pro — Claude Design Brief
**Version:** 1.0 (2026-05-01)
**Purpose:** 供 Claude Design 理解現況並繼續 UI/UX 視覺設計優化。
---
## 1. 專案概覽
| 欄位 | 內容 |
|------|------|
| 產品名稱 | EwoooC 商家後台(原名 MOMO Pro|
| 產品類型 | B2B 電商監控與管理系統(商品價格監控、活動管理、業績分析)|
| 語言 | 繁體中文 (zh-TW) |
| 渲染方式 | Server-side Jinja2 (Flask),無 SPA |
| CSS 框架 | Bootstrap 5.3.3 |
| 圖標庫 | Font Awesome 6.0.0 |
| 圖表 | Chart.js 3.9.1 + ECharts 5.4.3 |
---
## 2. 設計語言宣言
> **"Claude 暖系 × Nothing Phone 點陣機械感"**
### 核心哲學
- **底色**:溫暖米紙感(`#ebe6dc`)— 不刺眼的辦公室頁面底
- **主調**:焦糖橘(`#c96442`)— 暖而有力的品牌色,取自 Claude AI 色調
- **黑白對比**Nothing Phone 風格的純黑側欄(`#1a1a1a`)搭配鮮明白字
- **排版**:標題用 JetBrains Mono 等寬字,機械儀表板感;內文用 Inter + Noto Sans TC
- **裝飾**8px 點陣背景dot matrix作為深色卡片的背景紋路
- **陰影哲學**:線條優先(`1px solid rgba(...)`避免大陰影方角為主radius 最大 6px
---
## 3. 兩套 Layout 系統(重要!現況)
目前有**兩個共存的 Base Template**,正處於從舊版遷移至新版的過渡期:
### 3-A. 舊版(`base.html` + `_navbar.html`
- **Layout**:頂部固定 Navbar全頁 container 排版
- **Navbar**:深藍漸層 `#1e3c72 → #2a5298`,固定頂部 `position: fixed`
- **背景**:淺灰冷色 `linear-gradient(135deg, #f5f7fa 0%, #e8ecf1 100%)`
- **Accent 顏色**:藍紫漸層 `#667eea → #764ba2`(舊品牌色,仍在多數頁面中)
- **使用頁面**`dashboard.html``sales_analysis.html``monthly_summary_analysis.html` 等主要功能頁
### 3-B. 新版(`ewoooc_base.html` + `ewoooc-tokens.css` + `ewoooc-shell.css`
- **Layout**CSS Grid Sidebar240px+ 主內容區Topbar 64px sticky
- **Sidebar**:純黑背景 `#1a1a1a`,白色文字,焦糖橘 accent 高亮
- **背景**:米色紙張感 `#ebe6dc`
- **Accent 顏色**:焦糖橘 `#c96442`(新品牌色)
- **使用頁面**`vendor_stockout/`、部分新功能頁面EwoooC 路由下的頁面)
**設計方向**:以 3-B 新版為目標方向,所有優化/新設計請對齊新版設計系統。
---
## 4. 完整 Design TokenSource of Truth
### 4.1 色彩系統
#### 背景層次(米色系)
```
--momo-bg-body: #ebe6dc ← 頁面底色(最深)
--momo-bg-surface: #faf7f0 ← 卡片表面(預設)
--momo-bg-elevated: #fdfaf3 ← 懸浮/選中卡片
--momo-bg-subtle: #e2dccf ← 分隔區塊底色
--momo-bg-muted: #cfc7b5 ← 更暗的區塊
--momo-bg-paper: #f3eee2 ← Sidebar 底色、特殊卡片
```
#### 文字層次(暖墨系)
```
--momo-text-primary: #2a2520 ← 主要內文
--momo-text-secondary: #645c52 ← 次要說明
--momo-text-tertiary: #9b9081 ← 標籤標題、placeholder
--momo-text-disabled: #c4baa8 ← 禁用狀態
--momo-text-inverse: #faf7f0 ← 深色背景上的白字
--momo-text-link: #c96442 ← 連結色
--momo-text-link-hover:#8f4530 ← 連結懸停
```
#### 主色調(焦糖橘)
```
--momo-accent: #c96442 ← 主 accentButton/Active/Badge
--momo-accent-50: #fbf2ef ← 極淡hover 背景)
--momo-accent-100: #f5e1d9 ← 淡(選中 tag 背景)
--momo-accent-200: #ecc3b3 ← 較淡
--momo-accent-500: #c96442 ← = accent
--momo-accent-600: #b1543a ← hover 按鈕
--momo-accent-700: #8f4530 ← active/pressed 按鈕
--momo-accent-soft: rgba(201,100,66,0.12) ← 懸停背景
```
#### 狀態色(去飽和,適配米色底)
```
成功 success: text #2a7a3f | bg #e3ebd9 | border #c5d4b0
危險 danger: text #b5342f | bg #f0d8d4 | border #d9b1ac
警告 warning: text #b88416 | bg #f3e7c4 | border #d9c590
資訊 info: text #2d5d80 | bg #d8e2ea | border #b5c5d2
```
#### 邊框與分隔線
```
--momo-border: #2a2520 (實線邊框)
--momo-border-light: rgba(42,37,32,0.16) ← 淡分隔線
--momo-border-focus: #c96442 ← 聚焦狀態
--momo-divider: rgba(42,37,32,0.12)
```
#### 導航色Nothing 黑)— Sidebar 專用
```
sidebar background: #1a1612深暖黑
nav-link hover bg: rgba(201,100,66,0.12)accent-soft
nav-link active bg: #c96442實色焦糖橘
nav-link active text: #faf7f0反色
status-card border: rgba(201,100,66,0.35)(橘色描邊)
```
### 4.2 Typography
#### 字型堆疊
```
Display標題: "JetBrains Mono", "Space Mono", "SF Mono", Menlo, Consolas, monospace
Body內文: "Inter", -apple-system, "PingFang TC", "Noto Sans TC", "Microsoft JhengHei", sans-serif
Mono數據: "JetBrains Mono", "SF Mono", Menlo, Consolas, monospace
```
#### 字型大小
```
xs → 0.75rem (12px) ← 極小標籤
sm → 0.8125rem (13px) ← 次要內文、導航項目
base → 0.9375rem (15px) ← 主要內文
lg → 1.0625rem (17px) ← 稍大內文
xl → 1.625rem (26px) ← 頁面主標題
2xl → 2.25rem (36px) ← 大數字顯示
```
#### 字重與行高
```
normal: 400 base line-height: 1.5
medium: 500 tight line-height: 1.15(標題)
semibold: 600 loose line-height: 1.7(長文)
bold: 700
black: 800品牌名稱、數字展示用
```
#### 特殊文字工具類
```css
.momo-display JetBrains Mono標題用搭配 font-feature-settings: "tnum", "ss01"
.momo-mono 等寬字體數字/代碼搭配 font-feature-settings: "tnum"
.momo-label JetBrains Mono 10pxfont-weight 600letter-spacing 0.12emtext-transform uppercase
用於分類標題狀態標籤 "監控" "營運" "系統"
```
### 4.3 間距系統8px 基數)
```
--momo-space-1: 0.25rem (4px)
--momo-space-2: 0.5rem (8px)
--momo-space-3: 0.75rem (12px)
--momo-space-4: 1rem (16px)
--momo-space-5: 1.5rem (24px)
--momo-space-6: 2rem (32px)
--momo-space-7: 3rem (48px)
--momo-space-8: 4rem (64px)
```
頁面內容區 padding`28px 32px 40px`desktop`20px 16px 32px`mobile
### 4.4 圓角系統(方角優先)
```
--momo-radius-sm: 2px (0.125rem) ← badge、code、shortcut
--momo-radius-md: 4px (0.25rem) ← 按鈕、輸入框、卡片 → 預設
--momo-radius-lg: 6px (0.375rem) ← 較大卡片、modal
--momo-radius-pill: 50rem ← 圓形按鈕、chip
--momo-radius-circle: 50% ← 頭像
```
> 注意舊版頁面dashboard.html使用更大的圓角16px~20px。新設計請用 4px~6px。
### 4.5 陰影系統(線條感優先)
```
--momo-shadow-sm: 0 0 0 1px rgba(26,26,26,0.08)
--momo-shadow-md: 0 0 0 1px rgba(26,26,26,0.10)
--momo-shadow-lg: 0 12px 40px -8px rgba(26,26,26,0.18), 0 0 0 1px rgba(26,26,26,0.10)
--momo-shadow-colored: 0 0 0 2px rgba(201,100,66,0.25) ← accent 聚焦輪廓
```
> 陰影哲學:主要靠 `1px solid border` 定義邊界,大投影只用於 Modal/Popover。
### 4.6 動畫系統
```
--momo-duration-fast: 0.12s ← hover/focus 狀態切換
--momo-duration-normal: 0.2s ← sidebar 展收、dropdown
--momo-duration-slow: 0.4s ← Modal 出現、頁面過渡
--momo-ease-in-out: cubic-bezier(0.4, 0, 0.2, 1)
--momo-ease-out: cubic-bezier(0, 0, 0.2, 1)
基礎過渡(所有互動元件預設):
color / background-color / border-color / box-shadow各 0.12s ease-in-out
```
特殊動畫:
```css
@keyframes momo-pulse-dot sidebar 底部爬蟲狀態 live dot2s 閃爍
@keyframes momo-fade-in 元素出現opacity + translateY 2px
@keyframes momo-slide-up Toast 進場opacity + translateY 12px
```
### 4.7 Z-Index 層級
```
1 → base
1000 → dropdown
1020 → sticky topbar
1030 → fixed elements
1040 → modal backdrop
1050 → modal
1060 → popover
1070 → tooltip
1080 → toast
```
### 4.8 Layout 尺寸
```
sidebar width: 240px
sidebar collapsed width: 72px1180px 以下自動切換)
topbar height: 64px
```
---
## 5. 版面結構(新版 EwoooC Shell
```
┌─────────────────────────────────────────────────────┐
│ .momo-shell (CSS Grid: sidebar | main) │
│ │
│ ┌──────────┐ ┌──────────────────────────────────┐ │
│ │ .momo- │ │ .momo-main-shell │ │
│ │ sidebar │ │ │ │
│ │ │ │ ┌──────────────────────────────┐│ │
│ │ Logo │ │ │ .momo-topbar (sticky, 64px) ││ │
│ │ Nav │ │ │ [hamburger] [search] [user] ││ │
│ │ Groups │ │ └──────────────────────────────┘│ │
│ │ │ │ │ │
│ │ Status │ │ ┌──────────────────────────────┐│ │
│ │ Card │ │ │ .momo-content (28px 32px pad) ││ │
│ │ │ │ │ {% block ewooo_content %} ││ │
│ │ │ │ └──────────────────────────────┘│ │
│ └──────────┘ └──────────────────────────────────┘ │
└─────────────────────────────────────────────────────┘
```
### Sidebar 細節
- **Logo 區**`momo-logo-mark`3×3 點陣格,黑底白點,右上角點空缺)+ `momo-brand-name`JetBrains Mono, 18px, 800 weight
- **Nav Group 標題**`.momo-label`10px 大寫等寬),右側延伸分隔線 `::after`
- **Nav Link**:左 icon16px+ label + 右側數字代碼opacity 0.48
- Default透明底暖墨字
- Hover`accent-soft` 背景rgba(201,100,66,0.12)
- Active`accent` 實色背景(#c96442),白字
- **Status Card**sidebar 底部,暖黑底 `#1a1612` + 橘色描邊 + 點陣背景紋,顯示爬蟲狀態
### Topbar 細節
-mobile 漢堡選單hidden on desktop
- 中左搜尋框flex-grow最大 480px`⌘K` 快捷鍵 badge
- 中右彈性空間
- 右側:排程時間 pill深黑底+橘邊)、圖示按鈕(問號/鈴鐺)、使用者 chip頭像+姓名+角色)
---
## 6. 元件規格
### 6.1 按鈕
#### Primary ButtonCTA
```
背景:--momo-accent (#c96442)
文字:--momo-text-inverse (#faf7f0)
邊框none
圓角:--momo-radius-md (4px)
Hover--momo-accent-600 (#b1543a)
Active--momo-accent-700 (#8f4530)
Padding9px 20px
Font0.875rem600 weight
```
#### Secondary / Ghost Button
```
背景transparent
文字:--momo-text-primary (#2a2520)
邊框1px solid --momo-border-light
圓角4px
Hoverbg --momo-bg-subtle
```
#### Danger Button
```
背景:--momo-danger (#b5342f)
文字white
```
#### Icon Button.momo-icon-button
```
尺寸36×36px
背景transparent
圓角4px
Hoverbg --momo-bg-subtle
Color--momo-text-secondary → primary on hover
```
### 6.2 卡片Card
```
背景:--momo-bg-surface (#faf7f0)
邊框1px solid --momo-border-light
圓角:--momo-radius-lg (6px)
陰影:--momo-shadow-sm
Padding24px (1.5rem)
Hover可選--momo-shadow-md
```
特殊:深色 Status Cardsidebar 底部)
```
背景:--momo-ink-strong (#1a1612)
邊框1px solid rgba(201,100,66,0.35)
點陣背景紋路radial-gradient dots6px×6px
文字rgba(250,247,240,0.55) 標題 / rgba(250,247,240,0.62) 內文
```
### 6.3 表格
```
Bordernone預設行底部 border-bottom: 1px solid --momo-divider
Header--momo-bg-paper 底色,--momo-label 樣式欄位標題
Hover Row--momo-accent-soft 背景
Cell Padding12px 16px
Data 數字:.momo-mono 字體
狀態 Badgepill 形border-radius: 2px對應狀態色
```
### 6.4 徽章Badge
```
圓角2px方角
Font10px800 weight全大寫
Color--momo-text-inverse (#faf7f0)
背景:--momo-accent主要或對應狀態色
Padding1px 6px
```
### 6.5 搜尋框(.momo-search-box
```
高度38px
背景:--momo-bg-paper
邊框1px solid --momo-border
圓角4px
Placeholder--momo-text-secondary
Focus border--momo-accent
左側 iconfa-searchmargin-right 10px
右側⌘K shortcut badgeaccent 背景2px 圓角)
```
### 6.6 Toast 通知
```
位置右上角固定top: 24px, right: 24pxz-index: 1080
寬度max 360px
圓角6px
自動消失3秒
進場動畫slide-upopacity + translateY 12px → 0
類型色:成功綠 / 危險紅 / 警告黃 / 資訊藍
```
### 6.7 Modal
```
背景:--momo-bg-surface
圓角:--momo-radius-lg (6px)
Header--momo-ink 背景,白字(舊版用 #667eea 漸層,新版請改用暖墨色)
Backdroprgba(26,26,26,0.70)
最大寬度sm 400px / md 640px / lg 960px / xl 1140px
```
### 6.8 用戶頭像 Chip.momo-user-chip
```
高度40px
Padding4px 10px 4px 4px
圓角pill50rem
Avatar32×32px 圓形,背景 --momo-ink白字13px 800weight
Hoverbg --momo-bg-subtle
```
### 6.9 點陣裝飾(.momo-dot-bg
```css
background-image: radial-gradient(circle, rgba(26,26,26,0.12) 1px, transparent 1px);
background-size: 8px 8px;
```
用於深色背景卡片Status Card或特殊區塊裝飾。
---
## 7. 導航結構
```
Sidebar Nav
├── 【監控】
│ ├── 01 商品看板 / → fa-border-all
│ ├── 02 活動看板 /edm → fa-bullhorn
│ └── 03 分析報表 /sales_analysis → fa-chart-line
├── 【營運】
│ ├── 04 廠商缺貨 /vendor-stockout → fa-box-open
│ ├── 05 AI 助手 /ai_recommend → fa-wand-magic-sparkles
│ └── 06 雲端匯入 /auto_import → fa-download
└── 【系統】
└── 07 系統管理 /settings → fa-gear
```
舊版 Navbarbase.html 頁面)另有獨立下拉選單結構(業績分析/AI助手/系統管理各含多個子項目)。
---
## 8. 主要頁面清單
> **完整逐頁深度盤點請見 [`claude_design_brief_pages.md`](claude_design_brief_pages.md)Appendix A**
> 該附錄涵蓋 41 個 template + 3 個 component每頁包含路徑/路由/Layout/區塊/元件/互動/配色/設計問題/改造重點 9 個欄位。
### 8.1 設計風格分布總覽(深掃後校正)
實際發現 **4 種視覺風格混雜**,不只 2 種:
| 風格 | 背景 | Accent | 頁面數 | 處置 |
|------|------|--------|--------|------|
| **A. 深藍 + 藍紫漸層**(舊主流)| `#f5f7fa` | `#1e3c72→#2a5298` + `#667eea→#764ba2` | 23+ | **全部遷移至 B** |
| **B. 焦糖橘暖系**(目標) | `#ebe6dc` | `#c96442` | 6+ | 維持並擴張 |
| **C. 紫色獨立入口頁** | `#667eea→#764ba2` | `#4F46E5` | 4 (login/403/maintenance/_loading) | 改用焦糖橘色相 |
| **D. GitHub Dark Terminal** | `#0d1117` | `#3fb950/#58a6ff/#bc8cff` | 2 (ai_automation_smoke/code_review) | 保留深色但與焦糖橘對齊 |
### 8.2 風格 B目標設計參考頁面
Claude Design 可直接參考這幾頁的 Pattern 作為其他頁面遷移的樣板:
| 頁面 | 路徑 | 為何是樣板 |
|------|------|-----------|
| `vendor_stockout_index_v2.html` | `/vendor-stockout` | 風格 B 最完整實作Hero+Pulse Box+KPI Grid+Flow Cards+Summary |
| `edm_dashboard_v2.html` | `/edm/dashboard_v2` | 含 Chart.js 整合的範例Modal 內動態載圖)|
| `vendor_stockout_import_v2.html` | `/vendor-stockout/import` | Dropzone + 多狀態面板File/Progress/Result/Error|
| `_ewoooc_shell.html` | (component) | Sidebar 導航結構與 Status Card |
### 8.3 重點優化頁面 Top 10
依照「使用頻率 × 設計債務 × 影響範圍」排序:
| 排名 | 頁面 | 行數 | 主要債務 |
|------|------|------|---------|
| 1 | `dashboard.html` | 1405 | 流量最大首頁,舊藍紫,無空狀態 |
| 2 | `sales_analysis.html` | 3165 | 系統最複雜頁,三種圖表庫並存 |
| 3 | `web/templates/vendor_stockout/list.html` | 1793 | 1600+ 行 inline JS 無模組化 |
| 4 | `daily_sales.html` | 1905 | 自訂月曆 878 行 CSS行動版爆表 |
| 5 | `settings.html` | 1650 | 巨型設定頁padding 重疊 bug |
| 6 | `monthly_summary_analysis.html` | 1473 | ECharts 待換 Chart.js |
| 7 | `edm_dashboard_v2.html` | 1130 | 已是 B 風格但 CSS 600+ 行待精簡 |
| 8 | `ai_recommend.html` | 1000+ | AI 互動 UX 流式輸出未實作 |
| 9 | `user_management.html` | 906 | 權限矩陣未視覺化 |
| 10 | `logs.html` | 872 | 篩選器邏輯複雜,最佳重構樣本 |
---
## 9. 色彩衝突說明(設計遷移中)
目前有**三種 Accent 色系混用**,這是技術債,新設計一律使用 **焦糖橘**
| 色系 | Hex | 出現位置 | 備注 |
|------|-----|---------|------|
| 焦糖橘 ✓ | `#c96442` | ewoooc 新版頁面 | **目標設計色** |
| 藍紫 ✗ | `#667eea → #764ba2` | dashboard.html、表格 header、按鈕 | 舊版,待替換 |
| 深藍 ✗ | `#1e3c72 → #2a5298` | 舊版 Navbar、base.html | 舊版,待替換 |
---
## 10. 響應式斷點
| 斷點 | 寬度 | 行為 |
|------|------|------|
| Desktop | ≥1180px | Sidebar 240px 全展開,顯示文字 |
| Collapsed | 1180px820px | Sidebar 收至 72px只顯示圖標 |
| Mobile | ≤820px | Sidebar 隱藏slide-in 抽屜式hamburger 按鈕出現 |
Topbar 漸進隱藏Container Query
- ≤1024px隱藏排程 pill
- ≤880px隱藏使用者名稱/角色
- ≤720px隱藏搜尋框文字
---
## 11. 圖表設計規範
### Chart.js折線圖、柱狀圖、圓餅圖
目前使用舊藍紫色系,應遷移至:
```
主線色:#c96442焦糖橘
輔助線:#b5342f暗紅下跌、#2a7a3f深綠上漲
Fill 漸層:從 rgba(201,100,66,0.3) → rgba(201,100,66,0.05)
格線rgba(42,37,32,0.06)(極淡)
Tooltip背景 rgba(26,26,26,0.88),白字,焦糖橘描邊
```
### ECharts複雜多維圖表
應使用同色系調色板,確保視覺一致。
---
## 12. 互動模式
| 模式 | 實現方式 |
|------|---------|
| 表格行點擊展開詳情 | onclick → Bootstrap Modal |
| KPI Card 點擊鑽取 | onclick → Modal + fetch API |
| 搜尋篩選 | form GET 提交(非 SPA |
| 操作回饋 | Toast 通知(右上角滑入) |
| 複製品號 | Clipboard API + 視覺回饋(文字變 ✅ 已複製)|
| 載入狀態 | Bootstrap spinner-border |
| 全頁載入 | 自訂 overlay 動畫WOOO 品牌)|
---
## 13. 品牌資產
### Logo 變體
```
logo.png → 標準 logo
logo_transparent.png → 透明底
logo_v4_gradient.png → 漸層版
logo_v4_glass.png → 玻璃質感
logo_navbar.svg → 導航列向量版
logo_circle.svg → 圓形版
```
### 品牌名稱
- 老品牌:**WOOO** / **WOOO TECH**
- 新品牌:**EwoooC**(等寬字體呈現,副標:「價格監控 V2」
### Logo Mark點陣格設計
```
3×3 格32×32pxgap 1.5pxpadding 5px
背景:--momo-ink (#1a1612),圓角 2px
點:圓形白點
中心格第5格空白
→ 點陣 ⠿ 風格Nothing Phone 美學
```
---
## 14. 當前設計亮點(可保留延伸)
1. **JetBrains Mono 標題** — 機械儀表板感,數字排版優秀
2. **點陣背景裝飾** — Status Card 深色背景上的橘色點陣,獨特品牌感
3. **Live Dot 動畫** — 橘色脈衝點,搭配發光陰影 `box-shadow: 0 0 8px #c96442`
4. **Nav Code 數字** — 每個導航項目右側的灰色數字代碼01~07Like a terminal
5. **焦糖橘 × 暖墨 × 米白** — 三色搭配溫暖而不俗氣
6. **⌘K 搜尋框** — 開發者友善,鍵盤優先設計
---
## 15. 當前設計弱點(優化方向)
1. **兩套設計系統未統一** — 舊版藍紫 vs 新版焦糖橘,視覺割裂感強
2. **Dashboard 主頁** — 流量最大的頁面仍用舊版,設計待升級
3. **大圓角** — 舊版 16~20px border-radius與新版方角設計衝突
4. **無 Dark Mode** — Design Token 已備妥,只缺 JS 實現
5. **Modal Header** — 舊版用藍紫漸層,應統一為暖墨色
6. **缺共用元件庫** — 卡片/表格/表單 Pattern 散落各頁面,未抽象化
7. **無 Focus Style** — Accessibility 待加強focus-visible 輪廓)
8. **空狀態 (Empty State)** — 多數頁面僅有文字,缺圖示/插圖
---
## 16. 技術限制(設計時須知)
- **無 CSS Build Tool**:無法使用 SCSS/PostCSS所有 CSS 必須是原生 CSS 或內嵌 `<style>`
- **無前端框架**:無 React/Vue互動依賴 Bootstrap 5 JS + Vanilla JS
- **CDN 引用**Bootstrap、Font Awesome、Chart.js 等均從 CDN 載入
- **Jinja2 模板**:設計元素需考慮 Flask 模板語法(`{{ variable }}``{% if %}`
- **Bootstrap 5 共存**:新設計的元件需能與 Bootstrap 5 Class 共存,不衝突
---
*此文件由 Claude Code 自動掃描 45+ 個 template 檔案及 CSS token 系統生成2026-05-01。*

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
# 🚀 EwoooC 部署標準作業程序 (SOP)
> **版本日期**: 2026-04-18 (依 ADR-008 修訂)
> **版本日期**: 2026-05-05 (依 ADR-008 / ADR-011 修訂)
> **目標主機**: `ollama@192.168.0.188` (經 `192.168.0.110` 跳板)
## 🛠️ 開發同步流程
@@ -19,18 +19,83 @@ scp -o ProxyJump=wooo@192.168.0.110 app.py ollama@192.168.0.188:/home/ollama/mom
scp -o ProxyJump=wooo@192.168.0.110 -r services/ ollama@192.168.0.188:/home/ollama/momo-pro/
```
若部署時在 110 → 188 的內層 `scp` 遇到 `Host key verification failed`,先在 110 修正 `known_hosts`,不要用 `StrictHostKeyChecking=no` 硬跳過:
```bash
ssh wooo@192.168.0.110 \
"ssh-keygen -R 192.168.0.188 && ssh-keyscan -H 192.168.0.188 >> ~/.ssh/known_hosts"
```
修正後先做只寫 `/tmp` 的 smoke確認 `scp``ssh` 都通再部署正式檔案:
```bash
ssh wooo@192.168.0.110 \
"printf smoke > /tmp/momo_scp_smoke.txt && \
scp /tmp/momo_scp_smoke.txt ollama@192.168.0.188:/tmp/momo_scp_smoke.txt && \
ssh ollama@192.168.0.188 'cat /tmp/momo_scp_smoke.txt && rm -f /tmp/momo_scp_smoke.txt' && \
rm -f /tmp/momo_scp_smoke.txt"
```
### 3. 重啟容器
檔案進入掛載目錄後,重啟容器以加載變更:
```bash
ssh -J wooo@192.168.0.110 ollama@192.168.0.188 "docker restart momo-pro-system"
ssh -J wooo@192.168.0.110 ollama@192.168.0.188 \
"cd /home/ollama/momo-pro && docker compose up -d --no-deps --force-recreate momo-app"
```
注意:
- 禁止使用 `docker compose ... --remove-orphans`
- 禁止影響 `momo-db` 的資料與容器生命週期。
- 若只同步文件、QA script、非 runtime 檔案,不需要重啟容器。
## 🏗️ 重大變更 (Rebuild)
若修改了 `Dockerfile` 或新增了 `requirements.txt` 套件:
```bash
ssh -J wooo@192.168.0.110 ollama@192.168.0.188 "cd /home/ollama/momo-pro && docker compose build momo-app && docker compose up -d momo-app"
ssh -J wooo@192.168.0.110 ollama@192.168.0.188 \
"cd /home/ollama/momo-pro && docker compose build momo-app && docker compose up -d --no-deps --force-recreate momo-app"
```
## 🎛️ AI 觀測台前端變更驗收
若修改以下任一類檔案,必須跑 AI 觀測台 QA 套件:
- `templates/admin/*observability*` 或任何 `/observability/*` 頁面 template。
- `templates/ewoooc_base.html``templates/components/_ewoooc_shell.html`
- `static/css/observability-system.css``web/static/css/observability-system.css`
- `routes/admin_observability_routes.py`
本地先跑:
```bash
./scripts/quick_review.sh --sync-observability-css
./scripts/quick_review.sh --check-observability-css
./scripts/quick_review.sh --observability-qa
```
若要指定非 production 入口:
```bash
./scripts/quick_review.sh --observability-qa --base-url https://mo.wooo.work
```
部署後再跑:
```bash
./scripts/quick_review.sh --observability-qa
```
QA 套件會檢查:
- `/health` 必須 HTTP 200 且包含 healthy marker。
- CD deploy gate 正反案例 self-test 必須通過。
- 10 個觀測台頁面必須 HTTP 200。
- 每頁必須包含自己的內容 marker。
- 不得外露 `Traceback``ProgrammingError``UndefinedError``relation "``查詢失敗:`
- `observability-system.css` 必須線上 HTTP 200且包含核心 token/class。
- `static/css/observability-system.css``web/static/css/observability-system.css` 必須一致。
CD 也會自動判斷觀測台相關變更:
- Deploy 前跑 `./scripts/quick_review.sh --check-observability-css`,確認 CSS mirror 已提交一致,不在 runner 內偷偷修。
- Deploy 前跑 `./scripts/quick_review.sh --observability-qa --skip-production`
- Deploy 後跑 `./scripts/quick_review.sh --observability-smoke --base-url https://mo.wooo.work --timeout 12`
- 若變更與觀測台無關CD 會跳過這組額外 QA避免拖慢一般後端部署。
- 觸發範圍包含觀測台 templates、shell/topbar、觀測台 CSS、`routes/admin_observability_routes.py``quick_review.sh``check_observability_*``observability_contract.py``sync_observability_css.py`
- 觸發判斷集中在 `scripts/check_observability_deploy_gate.py`,不要在 workflow 內新增第二份長 regex。
## 🔍 維運指令
- **查看日誌**: `docker logs -f momo-pro-system --tail 100`
- **進入資料庫**: `docker exec -it momo-db psql -U momo -d momo_analytics`

View File

@@ -15,12 +15,18 @@
### 常用操作
- **查看狀態**: `docker ps | grep momo`
- **查看日誌**: `docker logs -f momo-pro-system --tail 100`
- **重啟主應用**: `docker restart momo-pro-system`
- **熱重載主應用**: `docker kill -s HUP momo-pro-system`
- **精準重建應用容器**: `docker compose up -d --no-deps --force-recreate momo-app`
- **精準重建排程/Telegram**: `docker compose up -d --no-deps --force-recreate scheduler telegram-bot`
- **全面啟動**: `docker compose up -d`
- **進入資料庫**: `docker exec -it momo-db psql -U momo`
紅線:
- 禁止使用 `docker compose down``--remove-orphans`
- 禁止 stop/remove/recreate `momo-db`;資料庫生命週期需另走明確維護流程。
### 影像管理
- **重建影像**: `docker compose build --no-cache momo-pro-system`
- **重建影像**: `docker compose build --no-cache momo-app`
- **清理過期資源**: `docker system prune -f`
---
@@ -40,10 +46,10 @@
---
## ❄️ K8s 相關指令 (已撤除,備份存檔)
- **查看 Pod**: `kubectl get pods -n momo`
- **重啟 Deployment**: `kubectl rollout restart deployment/momo-app -n momo`
- **查看日誌**: `kubectl logs -f deployment/momo-app -n momo`
## ❄️ K8s / K3s 狀態
已撤除。EwoooC 正式 runtime 是 188 主機的 Docker Compose110 只作為 Gateway / Nginx / Gitea 等周邊服務主機。
若看到舊文件提到 Pod、Deployment、PVC 或叢集操作,先以 `docs/adr/ADR-008-actual-runtime-on-188.md``docs/adr/ADR-011-cross-project-resource-isolation.md` 為準,不要照抄舊叢集命令。
---
@@ -58,6 +64,12 @@
## 🆘 故障排除 (Troubleshooting) - 2026-04-28 實戰總結
### 0. 110 → 188 SCP 報 `Host key verification failed`
- **原因**: 110 的 `~/.ssh/known_hosts` 保留了 188 的舊 host key 或缺少目前 key導致部署檔案傳輸被 SSH 安全檢查擋下。
- **修復**: 在 110 執行 `ssh-keygen -R 192.168.0.188 && ssh-keyscan -H 192.168.0.188 >> ~/.ssh/known_hosts`
- **驗證**: 先把 `/tmp/momo_scp_smoke.txt` 從 110 傳到 188 的 `/tmp`,再用 `ssh ollama@192.168.0.188 'cat /tmp/momo_scp_smoke.txt'` 確認可讀,最後刪除 smoke 檔。
- **紅線**: 不要把正式部署指令改成長期 `StrictHostKeyChecking=no`;遇到 key 問題要修 known_hosts而不是關閉驗證。
### 1. 網站 502 Bad Gateway (Nginx 找不到後端)
- **原因**: 110 與 188 之間的 SSH 隧道中斷。
- **檢查**: 在 110 執行 `curl -I http://127.0.0.1:5003/health`
@@ -110,3 +122,20 @@
- **原因**: Blackbox 或外部探測打 Dashboard 首頁 `/`,會觸發商品看板與 PChome 比價重型查詢;少量 sync worker 被長請求佔滿時,輕量 `/health` 也會排隊逾時。
- **檢查**: `docker logs momo-pro-system --since 20m | grep 'Blackbox-Exporter'` 應只看到 `GET /health``docker stats momo-db` 若接近多核心滿載,需同步看 `pg_stat_activity``latest_momo` 類查詢。
- **修復**: 188 的 `monitoring/prometheus.yml` 與 110 的 `/home/wooo/monitoring/prometheus.yml` blackbox HTTP targets 必須使用 `/health`Gunicorn 保持 `worker_class=gthread``GUNICORN_THREADS=4``preload_app=False`
### 12. GCP-A Ollama refused / 110:11435 502
- **快速診斷**: 在 repo 根目錄執行 `scripts/ops/diagnose_ollama_gcp_failover.sh`。此腳本不需要 root也不會修改 nginx、Docker、GCP 或正式服務。
- **判讀**:
- `GCP-A direct /api/version` 失敗且 `GCP-B direct` 成功primary VM、防火牆或 Ollama 服務異常;應用層會走 GCP-A → GCP-B → 111但仍需修 primary。
- `110 proxy primary` 502 且 `110 proxy secondary` 成功110 的 `11435` 固定代理 GCP-A所以 primary 掛時舊 proxy 入口會失敗;需 110 root 才能改 nginx 或 reload。
- `GCP-B embed` 成功但耗時接近 30s表示 `bge-m3` runner 慢但可用;若經常超過 30s應處理 GCP-B runner/CPU/模型併發,不要把 111 納入背景 embedding。
- **GCP-A 修復方向**:
- 有 GCP/SSH 權限時,先確認 VM 是否開機、Firewall 是否開 `22``11434`、Ollama process 是否在 listen。
- 110 現況若 `ssh gcp-a``port 22: Connection refused`,代表目前跳板無法進主機,不能靠 momo-pro app 修復。
- **110 proxy failover 方向**:
- 需要 root`sudo nginx -t`、修改 `/etc/nginx/sites-enabled/110-ollama-proxy.conf``sudo systemctl reload nginx`
- 若要讓 `11435` 在 GCP-A 掛時 fallback 到 GCP-B必須明確標註這是 proxy failover不代表 GCP-A 已恢復host health 仍應以 direct GCP-A 探針為準。
- **紅線**:
- 不要把背景 `bge-m3` 任務改落 111。
- 不要用更長 timeout 掩蓋 GCP-A refusedGCP-A 是 primary infra blocker。
- 沒有 110 root 或 GCP SSH 權限時,只能完成診斷、文件與應用層降級,不能假裝已修復 primary。

View File

@@ -0,0 +1,71 @@
# 外部專業做法 Benchmark
> 用途:定期把外部電商、商品資料與 UX 專業做法轉成 EwoooC / MOMO Pro 的可執行產品準則。
## 固定節奏
- 每週一 09:30 執行外部 benchmark自動輸出可落地建議。
- 只採用能改善核心價值的做法:商品身份比對準確率、可用比價覆蓋率、價格新鮮度、人工覆核效率、競品情報決策品質。
- 外部資料必須保留來源、讀取日期、觀察結論與不採用原因。
## 2026-06-02 初始觀察
### 1. 商品 identity 必須優先吃結構化 identifiers
Google Merchant Center 的商品資料規格把 `id``brand``gtin``mpn``price``availability` 視為商品資料核心Schema.org / Google Product structured data 也把 `Product``Offer``AggregateOffer``sku``gtin``brand``price``availability` 放在商品與報價語意中心。
落地到本產品:
- 比對引擎不能只靠商品名稱 token應逐步建立 `identity_evidence` 欄位分層保存品牌、SKU、GTIN/條碼、MPN/型號、容量、入數、色號、香味、款式。
- 若雙方有 GTIN / MPN / 明確型號,應優先作為 strong evidence。
- 若缺 GTIN / MPN不得自動推定同款要清楚標示 `identifier_missing``identifier_weak`
### 2. 價格可用性必須和 freshness 綁在一起
Google Merchant Center 要求價格與庫存狀態要和 landing page / checkout 保持一致Schema.org Offer 也有 `price``priceCurrency``availability` 等報價欄位。
落地到本產品:
- `decision_ready` 只能計入明確未過期價格,不應把未知 freshness 當可決策。
- Dashboard 必須拆開 identity coverage、fresh price coverage、pending identity、stale identity。
- 目前 V10.549-V10.565 的方向正確:未知新鮮度不得灌高覆蓋率,並要進刷新/救援流程。
### 3. 多 offer / 多平台比價應該呈現為 offer evidence不只是單一低價
Schema.org `AggregateOffer` 用於同一商品對應多個商家 offer。這個概念適合我們把 MOMO / PChome 的同款證據與價格證據分開保存。
落地到本產品:
- `competitor_prices` 應逐步從單一 match row演進成「identity pair + offer snapshot」兩層。
- PPT / AI 決策不只顯示價差,也要顯示 identity confidence、freshness、offer source、last crawled、manual review state。
### 4. Product comparison UX 要讓使用者比較規格差異
Baymard 的商品頁與比較 UX 研究強調:使用者需要清楚的 product comparison尤其是規格驅動品類。
落地到本產品:
- 人工覆核頁不能只列 MOMO/PChome 名稱與價格;要突出「不一致欄位」:色號、香味、容量、入數、套組、任選、效期、航空版。
-`identity_veto` / `true_low_confidence` 要顯示人可以理解的原因,不只顯示 `待審`
- Dashboard 建議下一步要直接連到對應操作:刷新、補抓、重評、單位價覆核、人工覆核。
## 目前不採用
- 不採用「只靠低價/高相似度自動配對」:價格相近不是 identity evidence。
- 不採用「大量放寬 threshold 來拉覆蓋率」:會污染核心比價資料。
- 不採用「把外部網站 UI 風格直接照搬」:只吸收資訊架構、證據呈現與工作流做法。
## 下一步 TODO 候選
1. 建立 `identity_evidence` 正規化 payload讓 matcher 回傳 identifier/spec/variant evidence。
2. 在覆核頁新增差異高亮:色號、香味、容量、入數、任選、效期、來源新鮮度。
3. 將 PPT / AI payload 的比價項目拆成 identity evidence 與 offer evidence。
4. 每週 benchmark 結果若命中上述 TODO回寫 `TODO_NEXT_STEPS.txt` 或新增 ADR / memory。
## 參考來源
- Google Merchant Center Product data specification: https://support.google.com/merchants/answer/7052112
- Google Search Central Product structured data: https://developers.google.com/search/docs/appearance/structured-data/product
- Schema.org Product / Offer / AggregateOffer: https://schema.org/Product, https://schema.org/Offer, https://schema.org/AggregateOffer
- Baymard Product Page UX Best Practices: https://baymard.com/blog/current-state-ecommerce-product-page-ux
- Baymard Product Comparison UX: https://baymard.com/blog/provide-comparison-features

View File

@@ -1,11 +1,12 @@
# Google Drive API 設定指南
## 📋 功能說明
系統自動化流程:
1. **每 30 分鐘**檢查 Google Drive `當日業績匯入` 資料夾。
2. **自動下載** `即時業績_當日.xlsx`
3. **自動匯入** 至資料庫 `daily_sales_snapshot`
4. **歸檔** 原始檔案
系統自動化流程PChome 後台業績匯出)
1. PChome 後台業績 Excel 先被放入 Google Drive `當日業績匯入` 資料夾。
2. `momo-scheduler` **每 30 分鐘**檢查待匯入檔案
3. 自動下載 `即時業績_當日.xlsx` 或符合設定 pattern 的 Excel
4. 自動辨識明細 worksheet / 表頭列,匯入至 `daily_sales_snapshot` 並同步 `realtime_sales_monthly`
5. 成功檔案歸檔至 `已匯入`;格式或日期不合格的檔案移至 `匯入失敗`,避免重複告警。
---
@@ -30,3 +31,6 @@ python3 -c "from services.google_drive_service import drive_service; drive_servi
## 📁 資料夾結構要求
Google Drive 根目錄必須存在:
`我的雲端硬碟/業績報表/當日業績/`
> 後續若要把 PChome 後台人工匯出改成全自動,先閱讀
> `docs/guides/pchome_sales_import_automation.md`。

View File

@@ -0,0 +1,128 @@
# AI 觀測台 UI Governance
> Scope: `/observability/*` pages using `ewoooc_base.html` and `.momo-observability-mode`.
## 目標
AI 觀測台是「AI 中樞控制室」,不是 Bootstrap 報表頁。任何新增或修改都必須維持暖色焦糖系、Noto Sans TC、點陣方格、卡片化資料面、可降級空狀態。
## 必守規範
- 使用 `static/css/observability-system.css` 的 token 與 utility class。
- 標題使用 `--obs-title-size`KPI 數字使用 `--obs-value-size`
- 圖表容器使用 `.obs-chart-frame``.obs-chart-frame-tall``.obs-chart-frame-slim`
- 頁面資料缺表或 migration 未完成時,顯示安全空狀態,不得把 SQL exception 顯示給使用者。
- 側欄必須維持暖深咖啡背景,第二/三層文字要有足夠對比。
- 表格必須有暖色表頭、row hover、長文字換行保護。
- 手機與中螢幕要能自動從多欄收成單欄。
## 禁止事項
- 不要在 template 裡新增 Times / Georgia / serif 作為主標題字型。
- 不要新增紫色系、純黑 sidebar、純白卡片 hover。
- 不要把整頁做成寬表格;資料密集內容優先用卡片、矩陣、可橫向 overflow 的表格。
- 不要硬寫超大 `font-size: clamp(...)`;先調 token。
- 不要新增 `style="height:..."` 圖表容器;使用 chart frame class。
- 不要用 `查詢失敗: ProgrammingError...` 顯示給使用者。
## 新頁 checklist
1. Template 設定正確 `active_page`,讓 `observability-system.css` 載入。
2. Hero 有清楚頁面任務,不做簡報封面式大字。
3. 第一屏有 3 到 6 個可行動 KPI不堆原始資料。
4. 主資料區先呈現結論,再給明細。
5. 空資料、缺表、外部服務未接入都要是可讀狀態。
6. 10 頁巡檢不得出現 `Traceback``UndefinedError``ProgrammingError``relation "``查詢失敗:`
## 驗收指令
### 1. Repo 靜態 UI guard
先跑本地 guard避免把已知 UI/UX 回歸重新帶進 repo
```bash
scripts/check_observability_suite.sh
```
若只想跑靜態檢查:
```bash
python3 scripts/check_observability_ui.py
```
如果修改了 `static/css/observability-system.css`,先同步 Flask 實際服務用的 mirror
```bash
python3 scripts/sync_observability_css.py
python3 scripts/sync_observability_css.py --check
```
或透過既有 quick review 選單執行第 8 項完整 QA 套件、第 6 項靜態 UI guard、第 9 項 CSS mirror sync
```bash
./scripts/quick_review.sh
```
非互動模式可直接用於部署腳本或 CI
```bash
./scripts/quick_review.sh --sync-observability-css
./scripts/quick_review.sh --check-observability-css
./scripts/quick_review.sh --observability-qa
```
指定不同環境時:
```bash
./scripts/quick_review.sh --observability-smoke --base-url https://mo.wooo.work
./scripts/quick_review.sh --observability-qa --base-url https://mo.wooo.work
./scripts/quick_review.sh --observability-qa --skip-production
```
Guard 會檢查:
- 觀測台頁面契約集中在 `scripts/observability_contract.py`,新增/改名頁面先改這裡。
- Times / Georgia 等非規範標題字型。
- SQL/Jinja exception 文案外露。
- 圖表 `style="height:..."` 與靜態 `style="width:..."`
- 過大標題 clamp 與純白 hover/card surface。
- 觀測台 CSS 必要 token / utility class 是否仍存在。
- 側欄是否維持 `AI 中樞 → AI 觀測台 → 分組頁面` 的收納結構。
- 側欄是否維持暖深咖啡背景與第二/三層足夠對比。
- Topbar 是否仍載入觀測台 CSS 與健康 indicator。
- 10 個觀測頁的 `active_page`、側欄 URL、側欄 label、`momo-observability-mode` 掛載清單是否一一對齊。
- 10 個側欄 URL 是否都在 `routes/admin_observability_routes.py` 有對應 Flask route。
- `static/css/observability-system.css` 與實際 Flask static 服務用的 `web/static/css/observability-system.css` 必須一致。
- CD deploy gate 的正反案例 self-test 是否通過。
### 2. Production 10 頁 HTTP 巡檢
建議使用 repo 內建腳本:
```bash
python3 scripts/check_observability_pages.py
```
或透過 quick review 選單執行第 7 項。
此巡檢不只檢查 HTTP 200也會檢查
- `/health` 必須回 200 且包含 healthy marker。
- 不得出現 framework / database exception 文案。
- 每頁必須包含自己的核心標題與內容 marker。
- 每頁必須載入 `momo-observability-mode``observability-system.css` 與 topbar AI 觀測台 indicator。
- `/static/css/observability-system.css` 必須能線上 200 載入,且包含核心觀測台 token/class。
- HTML 不能小到像空殼頁或錯誤 fallback。
```bash
python3 - <<'PY'
import urllib.request
pages=[('/observability/overview','總覽'),('/observability/agent_orchestration','Agent'),('/observability/business_intel','商業'),('/observability/host_health','主機'),('/observability/ai_calls','AI 呼叫'),('/observability/budget','預算'),('/observability/promotion_review','晉升'),('/observability/rag_queries','RAG'),('/observability/quality_trend','品質'),('/observability/ppt_audit_history','PPT')]
needles=['Traceback','UndefinedError','ProgrammingError','Internal Server Error','relation "','查詢失敗:']
for path,label in pages:
with urllib.request.urlopen('https://mo.wooo.work'+path,timeout=12) as r:
html=r.read().decode('utf-8','ignore')
found=[n for n in needles if n in html]
print(f'{label}: HTTP {r.status}, issues={found or "none"}')
PY
```

View File

@@ -0,0 +1,75 @@
# PChome 後台業績匯出自動化
## 目的
把目前人工從 PChome 後台匯出業績 Excel 的流程,自動接到既有匯入管線:
```text
PChome 後台業績匯出
-> Google Drive 當日業績匯入/
-> momo-scheduler 每 30 分鐘 auto_import
-> daily_sales_snapshot + realtime_sales_monthly
-> daily / growth / PPT / AI 分析
```
## 目前已完成
- V10.605 起,`services/import_service.py` 已可自動辨識 PChome 後台匯出的多工作表 Excel。
- 匯入器會掃描所有 worksheet 的前 15 列表頭,優先選擇含日期、商品名稱、總業績或銷售金額的明細工作表。
- 匯入成功後檔案會移到 `已匯入`
- 格式或日期不合格的檔案會移到 `匯入失敗`,避免每 30 分鐘重複告警。
- `daily_sales_snapshot."商品ID"` 是 PChome 後台業績匯出的商品識別碼,不可預設等於 MOMO `products.i_code`
## 推薦方案
### 方案 APChome 後台排程寄信或固定附件
這是首選。若 PChome 後台能排程寄出報表,或每日寄到 Gmail
1. PChome 後台每天固定寄出業績 Excel。
2. Gmail / n8n 監聽寄件者、主旨、附件檔名。
3. 驗證附件日期與檔名,例如 `即時業績_當日.xlsx``pchome_sales_YYYYMMDD.xlsx`
4. 將附件存到 Google Drive `當日業績匯入/`
5. 既有 `run_auto_import_task` 自動匯入。
優點:穩定、低維護、無需模擬登入、較不受後台 UI 改版影響。
### 方案 B受控瀏覽器自動下載
若 PChome 後台只能人工登入後匯出:
1. 在 110 或獨立 browser worker 跑 Playwright / n8n browser step。
2. 使用密鑰管理保存帳密,不寫入 repo。
3. 登入 PChome 後台,選日期範圍,下載業績 Excel。
4. 檢查下載檔大小、sheet、日期最大值。
5. 上傳到 Google Drive `當日業績匯入/`
6. 交由既有 importer 匯入。
注意:若有 OTP、驗證碼、裝置信任或密碼到期此方案需要 HITL fallback不應讓瀏覽器在使用者 Mac 上反覆跳出授權視窗。
### 方案 CTelegram 上傳備援
若 PChome 後台登入自動化暫時不穩:
1. 使用者將 Excel 直接丟給 Telegram bot。
2. bot 驗證檔案名稱、日期、sheet、欄位。
3. 通過則存到 Google Drive 或直接呼叫 importer。
4. 不通過則回覆可讀錯誤,例如缺欄位、資料過舊、找不到明細 sheet。
此方案不是全自動,但可以把「下載後匯入」從人工操作降到傳檔即可。
## 實作順序
1. 先確認 PChome 後台是否支援排程寄信、Email 附件、FTP、API 或固定下載 URL。
2. 若有 Email / 附件,優先用 n8n / Gmail API 走方案 A。
3. 若沒有,再做方案 B 的 browser workerworker 不跑在使用者桌面,避免密碼提示與彈窗干擾。
4. 保留方案 C 作為緊急備援。
5. 每次自動取得檔案後,都先跑 importer 的 sheet / 日期 / 欄位 preflight再進正式匯入。
## 驗收條件
- 不需人工打開後台即可產生或取得當日 PChome 業績 Excel。
- Google Drive `當日業績匯入/` 有新檔後30 分鐘內自動匯入。
- `daily_sales_snapshot``realtime_sales_monthly` 最新日期落後不超過 1 天。
- `/daily_sales``/growth_analysis` 圖表 smoke 通過。
- 失敗檔只告警一次,並被移到 `匯入失敗`

View File

@@ -0,0 +1,73 @@
# Webcrumbs 共用 UI Runtime 接入手冊
> 目的:讓 momo-pro 與其他專案共用同一套自架 Webcrumbs microfrontend runtime避免每個專案各自引用官方 CDN 或複製 runtime。
## 定位
- Webcrumbs 在本專案只作為 microfrontend/plugin loader。
- 不把 Webcrumbs 上游 repo 整包放進 momo-pro 主服務。
- 不依賴官方 `app.webcrumbs.ai` 或官方 `cdn.webcrumbs.dev/@latest`
- 生產環境必須走自架 runtime並固定版本。
## momo-pro 設定
`.env` 建議值:
```env
WEBCRUMBS_ENABLED=true
WEBCRUMBS_BASE_URL=https://webcrumbs.wooo.work
WEBCRUMBS_RUNTIME_VERSION=shared-ui-poc-0.1.0
WEBCRUMBS_RUNTIME_PATH=/webcrumbs-assets/loader/webcrumbs-compatible-loader.js
WEBCRUMBS_RUNTIME_URL=
WEBCRUMBS_PLUGIN_BASE_URL=/webcrumbs-assets/plugins
WEBCRUMBS_ASSET_UPSTREAM_URL=http://192.168.0.188:18088
```
目前正式頁面預設走 momo-pro 同源 asset proxy
- `/webcrumbs-assets/loader/...`
- `/webcrumbs-assets/plugins/...`
- `/webcrumbs-assets/demo/...`
這樣即使 `webcrumbs.wooo.work` 的公網 TLS 或 Basic Auth 尚未完全收斂momo-pro 頁面仍可用 `mo.wooo.work` 同源載入 loader 與 plugin。若日後要改回獨立 Webcrumbs CDN直接設定
```env
WEBCRUMBS_RUNTIME_URL=https://webcrumbs.wooo.work/shared-ui/loader/webcrumbs-compatible-loader.js
WEBCRUMBS_PLUGIN_BASE_URL=https://webcrumbs.wooo.work/shared-ui/plugins
```
## 頁面嵌入方式
全站 runtime 由 `templates/ewoooc_base.html` 載入。頁面只需要放 plugin tag
```html
<stock-platform-plugin uri="/webcrumbs-assets/plugins/finance.market-ticker-strip/0.1.0"></stock-platform-plugin>
```
Plugin 目錄至少應提供:
```text
bundle.js
style.css
```
## 治理規則
- Plugin URI 必須使用自架 domain。
- 在 momo-pro 正式頁面,優先使用同源 `/webcrumbs-assets/` URI。
- Plugin 目錄必須版本化,不使用浮動 `latest`
- Plugin 不得包含 secret、token、內部 API key。
- Plugin 若需要正式資料,必須讀 momo-pro 既有 API不得自行打 DB。
- 修改 Webcrumbs runtime 本體時需注意 AGPL-3.0 授權義務。
## 驗收
- `/webcrumbs` 顯示 runtime URL、版本與 plugin base。
- `/webcrumbs` 會嵌入同源 `/webcrumbs-assets/plugins/...` 的 live plugin preview並由 momo-pro 注入只讀 MOMO/PChome exact 價差摘要;若資料源不可用或無風險候選,改注入診斷空狀態,避免 plugin fallback demo 數字在正式頁面被誤認成真實市場或 AI 建議。
- `/api/webcrumbs/marketplace-host-data` 會回傳同一份登入後只讀 host data contract供 plugin / QA / 其他專案 proxy 驗證;即使全站 `DISABLE_LOGIN=true`,此 API 仍必須要求登入 session 或 `X-Internal-Key`boundary 必須標示 `writes_database=false``calls_llm=false``fetches_external=false`
- Host data metadata 需同時輸出 `matched_count/coverage_rate``fresh_match_count/fresh_match_rate/stale_match_count/pending_match_count`,讓共用 UI 分清「身份覆蓋」與「價格新鮮度」。
- `/webcrumbs` 未取得登入 session 或 `X-Internal-Key` 時只能注入 `auth_required` 空狀態,不得把真實 SKU、價格或價差寫進 inline seed data。
- `/webcrumbs-assets/loader/webcrumbs-compatible-loader.js` 回 200 且 content type 是 JavaScript。
- 若 Shared UI Hub 或 `WEBCRUMBS_ASSET_UPSTREAM_URL` 暫時不可用,`/webcrumbs-assets/loader/webcrumbs-compatible-loader.js` 必須回 200 的本地 fallback loader避免正式頁面出現 502fallback 只負責安全降級與標示 runtime 離線,不取代真實 plugin bundle。
- `ewoooc_base.html``WEBCRUMBS_ENABLED=true` 且 runtime URL 有效時輸出 `<script data-webcrumbs-runtime=...>`
- 任一試點頁嵌入 plugin 後,瀏覽器 console 不應有 `MISSING_URI``STYLE_LOAD_ERROR``SCRIPT_LOAD_ERROR`

View File

@@ -0,0 +1,207 @@
# LLM 模型完整評估 — Operation Ollama-First v5.0
> **日期**2026-05-04
> **目的**:評估 momo-pro 各場景對應的最佳 LLM 模型,並啟動建議模型
> **整體原則**Ollama-first免費→ Frontier API鎖定 5+ 場景)→ 規則引擎兜底
---
## 一、場景 × 模型對應矩陣
### 1.1 戰術層高頻、結構化、Ollama-only
| 場景 | 既有模型 | 建議模型 | 為何 |
|---|---|---|---|
| **Hermes 競價分析** (4h × 300 SKU) | `hermes3:latest` (8B) | 維持 + `qwen3:14b` 升級鏈 | 8B 處理 95% 案例足夠;複雜 SKU 升級 14B |
| **Hermes 意圖分類** (Telegram NLP) | `hermes3:latest` | 維持 | 結構化 JSON 輸出穩定 |
| **NemoTron 威脅分派** | NIM 8B / `qwen3:14b` (flag) | `qwen3:14b` 為主 | A2 確認 qwen3 原生支援 tools |
| **AiderHeal 修 Code** | `qwen2.5-coder:7b` | **升 `qwen2.5-coder:32b`** ⭐ | 程式碼能力 +30%(接近 Opus 4.6|
| **Sales Copy 文案** | `llama3.1:8b` | `gemma3:4b` (輕量) | 短文案不需 8B |
### 1.2 戰略層(低頻、敘事型、鎖定 Frontier
| 場景 | 鎖定模型 | 為何鎖定 |
|---|---|---|
| **OpenClaw 週報** | `gemini-2.5-flash` 🔒 | 長 context + 繁中商業文體 |
| **OpenClaw 月報** | `gemini-2.5-flash` 🔒 | 同上 |
| **OpenClaw 日報洞察** (200 字) | `gemini-2.5-flash` 🔒 | 精簡敘事 |
| **OpenClaw Q&A** (Telegram) | `qwen3:14b` (主) → Gemini fallback | A7 已切flag ON |
| **Code Review 高階評估** | **Claude Opus 4.7** (Phase 7 待 KEY) | Arena Elo 1548 (#1) |
| **EA HITL 戰略決策** | `gemini-2.0-flash` (現) → Claude Sonnet 4.6 候選 | agentic 工具使用佳 |
### 1.3 多模態與專用
| 場景 | 模型 | 已拉? |
|---|---|---|
| **Embedding (KM/RAG)** | `bge-m3:latest` (1024 維) | ✅ Primary + Secondary |
| **PPT 視覺檢查** (Phase 14) | `minicpm-v:latest` (主) + `llava` (備援) | ✅ Primary + Secondary minicpm-v / 拉 llava ⏳ |
| **深度推理** (DeepSeek-R1) | `deepseek-r1:14b` | 拉中 ⏳ |
### 1.4 雲端 API鎖定 Frontier
| 供應商 | 模型 | 用途 |
|---|---|---|
| **Anthropic** | `claude-opus-4-7` | Code Review #1 (Arena 1548) |
| **Anthropic** | `claude-sonnet-4-6` | EA HITL 候選agentic|
| **Google** | `gemini-2.5-pro` | MCP Grounding聯網|
| **Google** | `gemini-2.5-flash` | 週/月/年報、Q&A fallback |
| **Google** | `gemini-2.0-flash` | PPT 簡報、EA HITL |
| **DeepSeek** | `deepseek-chat` (V3.2) | OpenRouter 直連備援 |
| **DeepSeek** | `deepseek-reasoner` (R1-0528) | 推理鏈備援 |
| **NVIDIA NIM** | `meta/llama-3.1-8b-instruct` | NemoTron fallback |
| **NVIDIA NIM** | `nvidia/llama-3.3-nemotron-super-49b-v1.5` | ElephantAlpha 49B |
---
## 二、本次啟動的追加模型
### 2.1 Primary 34.143.170.20 (oleetsai)
```bash
# 既有Phase 0-19 累積)
✅ bge-m3:latest (1.2GB) — Embedding
✅ hermes3:latest (4.7GB) — Hermes 主
✅ qwen2.5-coder:7b (4.7GB) — AiderHeal
✅ qwen3:14b (9.3GB) — Q&A / Nemotron 升級
✅ qwen2.5:7b-instruct (4.7GB) — Q&A 預設
✅ minicpm-v:latest (5.5GB) — PPT vision
# 本次追加(背景拉中)
⏳ qwen2.5-coder:32b (~20GB) — AiderHeal 32B 升級
⏳ deepseek-r1:14b (~9GB) — 推理鏈備援
⏳ llava (~5GB) — Vision 備援
⏳ gemma3:4b (~3GB) — 輕量 sales_copy
預計總容量:~60GB
```
### 2.2 Secondary 34.21.145.224 (owen_taipei)
```bash
# 本次新建立連線後拉(與 Primary 同步)
✅ bge-m3:latest (剛同步)
✅ hermes3:latest (剛同步)
✅ qwen2.5-coder:7b (剛同步)
✅ qwen3:14b (剛同步)
✅ qwen2.5:7b-instruct (剛同步)
✅ minicpm-v:latest (剛同步)
⏳ qwen2.5-coder:32b (背景拉中)
⏳ deepseek-r1:14b (背景拉中)
⏳ llava (背景拉中)
⏳ gemma3:4b (背景拉中)
```
---
## 三、各場景升級路線(戰役後續)
### Phase 21建議模型對應路由優化
| 場景 | 路由規則 |
|---|---|
| Sales Copy < 100 字 | `gemma3:4b`(輕量快) |
| Sales Copy ≥ 100 字 | `llama3.1:8b`(既有) |
| Hermes 簡單比價 | `hermes3:latest` |
| Hermes 複雜分析 (gap > 20% / 銷量大跌) | `qwen3:14b` 升級 |
| AiderHeal 簡單修補 | `qwen2.5-coder:7b` |
| AiderHeal 重構級 | `qwen2.5-coder:32b` ⭐ |
| EA HITL 明確威脅 | Hermes 規則引擎(免費)|
| EA HITL 戰略決策 | `claude-sonnet-4-6` 候選 |
| 推理需求chain-of-thought| `deepseek-r1:14b` |
| PPT 視覺檢查 | `minicpm-v:latest``llava` 備援 |
### Phase 22建議API 直連 + 多供應商編排
```
┌──────────────────────────────┐
│ CostThrottle (Phase 20) ⭐ │
│ 超預算 110% 自動切 fallback │
└────────────┬─────────────────┘
┌────────────────────────┼────────────────────────┐
│ │ │
Code Review EA HITL Q&A 戰略
│ │ │
Claude Opus 4.7 Gemini 2.0 Flash qwen3:14b
↓ throttle ↓ throttle ↓ low quality
Gemini 2.5 Flash Hermes 預跑兜底 Gemini 2.5 Flash
↓ throttle ↓
ElephantAlpha 49B Hermes 規則引擎
```
---
## 四、儲存空間 + 性能評估
### 4.1 GCP 預期用量
- 每台 GCP 約 60GB Ollama 模型Primary + Secondary 各一份冗餘)
- 12 個模型 × 平均 5GB = 60GB
- 假設 GCP VM 100GB SSD → 60% 使用率,可控
### 4.2 RAM 載入
- Ollama keep_alive=24h 可保留熱模型hermes3 / qwen3:14b 永駐留)
- 冷模型minicpm-v / llava首次調用 ~10s 加載
- 解:分批載入 + 配置 OLLAMA_NUM_PARALLEL=2 限制同時載入數
### 4.3 推論延遲GCP SSD
| 模型 | 預期延遲256 tokens |
|---|---|
| gemma3:4b | ~1.5s |
| hermes3:latest | ~3s |
| qwen2.5:7b-instruct | ~3s |
| qwen3:14b | ~6s |
| deepseek-r1:14b | ~8s含 thinking|
| qwen2.5-coder:32b | ~12s |
| minicpm-v:latest | ~10s含 image |
---
## 五、模型治理規範(補強 ADR-028
### 5.1 新增模型 SOP
1. 評估 ROI場景對應 + 預期降本/升質量化)
2. SSH GCP Primary 試拉確認 size + 推論延遲
3. 加進 ai_call_logger COST_TABLE
4. 加 caller × model 路由規則
5. unit test 驗 routing
6. 灰度啟用feature flag
7. 1 週觀察後正式啟用
### 5.2 既有模型替換 SOP
1. A/B 測試新舊模型對 10+ 黃金樣本
2. 統帥盲測通過後才替換
3. 舊模型保留為 fallback不立刻刪
4. 寫進 ADR
### 5.3 模型淘汰 SOP
1. 連續 7 日 0 流量 → 標記 deprecated
2. 30 日仍 0 流量 → SSH GCP 刪除節省空間
3. ADR 註明淘汰原因
---
## 六、與 ai_call_logger COST_TABLE 對齊
| Model | Cost (in/out per M) | 為何 |
|---|---|---|
| 全 Ollama 模型 | 0 / 0 | 自架免費 |
| gemini-2.5-pro | $1.25 / $10.0 | 高品質 |
| gemini-2.5-flash | $0.075 / $0.30 | 性價比 |
| claude-opus-4-7 | $15 / $75 | 程式碼 #1 |
| claude-sonnet-4-6 | $3 / $15 | 平衡 |
| claude-haiku-4-5 | $0.8 / $4 | 輕量 |
| deepseek-chat | $0.014 / $0.28 | 直連最便宜 |
| deepseek-reasoner | $0.14 / $2.19 | 推理 |
| NIM 系列 | 0 / 0 | 配額制 |
---
## References
- ADR-027 附錄(三主機架構)
- ADR-028LLM 路由統一準則)
- ADR-029Hermes-First 雙塔分工)
- ADR-030Frontier 多供應商策略)
- `services/ai_call_logger.py` COST_TABLE
- `services/llm_caller_registry.py` CALLER_REGISTRY
- `docs/operation_ollama_first_v5_postmortem.md`

View File

@@ -13,19 +13,30 @@
| 檔案 | 用途 | 何時閱讀 |
|---|---|---|
| `history_logs.md` | 重大里程碑與歷史脈絡 | 要理解演進背景、排查「為何變成這樣」時 |
| `current_execution_queue_20260524.md` | 目前核心產品推進佇列涵蓋比價、圖表、PPT、觀測台、外部入口、效能與部署驗證 | 接續本輪「批准繼續」、避免漏掉工作項目、需要新 session 交接時 |
| `ai_automation_closure_20260429.md` | 四 AI Agent 自動化閉環、Smoke、metrics 與 Grafana 觀測實況 | 接續 AI 自動化、EventRouter、AutoHeal、OpenClaw memory、ElephantAlpha 編排、可觀測性時 |
| `credentials_passbook.md` | 伺服器、帳密、埠位對照 | 需要維運、部署、憑證核對時 |
| `feedback_db_metadata_import.md` | SQLAlchemy metadata / `create_all()` 漏表鐵律 | 新增 model、修 schema、排查 fresh env 漏表時 |
| `db_connection_pool_singleton_20260430.md` | PostgreSQL `too many clients` 連線池放大事故與 DatabaseManager singleton 修正 | 排查 DB 連線數暴增、route 內反覆初始化 DatabaseManager、SQLAlchemy engine/pool 行為時 |
| `project_phase38_56_observability_war_room.md` | Phase 38→56 AI 觀測台戰役落地盤點、已知缺口與後續拆分方向 | 接續觀測台頁面、Telegram 指令、scheduler probe、AutoHeal/CodeReview L2 入口、Chart.js polish 或 deploy_doctor 時 |
| `observability_ui_qa_guardrails_20260505.md` | AI 觀測台 UI/UX guard、production smoke、CSS mirror 與 quick review 非互動入口 | 修改 `/observability/*` 前端、側欄、topbar、Chart.js、CSS 或部署觀測台前端變更時 |
| `project_phase3f_cleanup_roadmap.md` | ADR-017 執行矩陣與階段紅線 | 正在做 3f 模組化收尾時 |
| `code_modularization_inventory_20260430.md` | Python 大檔盤點、分層規範與拆分工作項目 | 新增功能、拆大檔、審查是否違反模組化治理時 |
| `schema_inventory_baseline.md` | DB 表分類與 drift 基線 | 要收斂 migration / ORM / raw SQL 真相時 |
| `frontend_v3_handoff_20260512.md` | 前端 V3 守門落地、正式部署、UI/UX 響應式缺口與接續順序 | 新 session 接續前端 V3 全站 UI/UX、手機版確認、`/daily_sales``/edm` 修正與部署時 |
| `claude_inventory_validation_20260513.md` | Claude Code V1/V2 盤點逐項驗證、已修項與不可盲動清單 | 接續盤點整改、判斷某項是否仍是阻擋、避免重複清已修項時 |
## 關聯 Guide
- `docs/guides/codex_agent_roles.md`
用途12 位歷史 Agent 的 Codex 化角色矩陣。
何時閱讀要做多角色分工、任務派工、review 流程設計時。
- `docs/guides/observability_ui_governance.md`
用途AI 觀測台 `/observability/*` 頁面的 UI/UX 設計治理、禁用事項與巡檢指令。
何時閱讀新增或修改觀測台頁面、側欄、Chart.js、資料密集卡片/表格、空狀態時。
- `docs/guides/pchome_sales_import_automation.md`
用途PChome 後台業績匯出自動化,銜接 Google Drive auto import、失敗隔離與下游 daily/growth/PPT/AI。
何時閱讀:要把 PChome 後台業績匯出從人工下載改成 Email / n8n / browser worker / Telegram 備援自動化時。
## 新增規則

View File

@@ -0,0 +1,209 @@
# Claude Code 盤點驗證記憶2026-05-13
> 用途:接續 V1/V2 全棧盤點整改時,先看這份,避免把已修或已過期的項目重複當成阻擋。
## 已驗證並修補
- `rag_query_log.saved_call`:已改為只有高信心 RAG 命中且跳過 LLM 時寫 `true`,並補測試。
- `ai_calls.rag_hit`logger API 原本可寫但缺回歸測試;已補 `set_rag_hit(True)` 寫入測試。
-`SSH_JUMP_* / SSH_TARGET_*`Python caller 已不存在;已從 `config.py``.env.example` 範例移除,執行路徑以 `ELEPHANT_ALPHA_JUMP_*` 為準。
- `filesystem-mcp``MCP_BASE_HOSTS` 與 health check 已存在;已補 `ops_diagnostics` 唯讀工具白名單,並測試 `read_file` 可通、`write_file` 被拒。
- `mcp_calls.status`:已補 `ok/cache_only/timeout/rate_limited/error` 細分,早退結果也會帶 `status='error'`
- Telegram `cat_` callback主 OpenClaw route 不是問題polling bot helper 的預設 `cat` 才是潛在漏 handler。已改預設為既有 handler `trend` 並補測試。
- Scheduler 觀測任務BGE-M3 embedding consistency 不一致、host health probe、AI error spike、觀測台日報與 cleanup 例外都已接 `_notify_scheduler_failure()`
- AutoHeal Telegram inline`obs_heal` 已用 `_CURRENT_USER_ID_CTX` 記錄實際 Telegram userwebhook request 開頭會清空 stale user context。
- 匯入檔名日期 helper`routes/import_routes.py` 已改用 `utils.text_helpers.extract_snapshot_date_from_filename()` 單一來源,並用真實日期解析拒絕 `20261399` 這類不可能日期。
- `monthly_summary_analysis` 匯入已守住「刪同年月後 append」路徑`tests/test_import_service_sql_params.py` 會防止該月結匯入區塊退回整表 `if_exists='replace'`
- ROI 月報 feedback 區塊:反饋趨勢查詢失敗仍不阻擋月報,但已改為 warning + stack避免完全靜默。
- Elephant Alpha short-circuit`log_ai_call` 遙測失敗仍不阻擋省成本 return但已改為 warning + stack。
- Claude cost throttle成本節流檢查失敗仍維持 Claude 可用,但已改為 warning + stack避免成本保護失效無跡可查。
- `ai_call_logger` caller registryregistry 匯入失敗仍不阻擋 LLM 遙測,但已改為 warning + stack。
- Observability routepromotion review RAG 相似查詢、PPT audit history 缺表、host health probe 寫入、MCP 24h summary 缺表等 fail-safe 區塊已改成 debug/warning log不再完全靜默。
- Google Drive import`services/import_service.py` 的日期 `IN (...)` 刪除/驗證查詢已改為 SQLAlchemy bind params不再把 DataFrame 日期值拼進 SQL 字串。
- OpenClaw Bot中文字型下載、趨勢同期 DB 查詢、匯入格式業績預覽解析等 best-effort 區塊已補 debug/exception/warnings避免真正錯誤完全無跡可查。
- Telegram polling bot舊 callback 正規化失敗、空 `momo:eig:` event_id 回覆失敗仍保持 fail-safe但已補 debug log。
- `ai_call_logger._write_to_db` 不是死函數:它是 `_async_write()` 的 daemon thread target`infer_caller_from_stack()` 確認無 caller 後已移除。
- `cache_manager.FingerprintCache` 與 dashboard shared cache 清理維持 fail-open / best-effort但已補 debug log避免 cache fingerprint 或檔案清理失敗完全沉默。
## 已驗證為已修或過期
- migration / ORM`032` 已入庫,`033` host label、`034` embedding_signature、`035` business baseline、`036` incidents 雙欄、`037` action_plans guardrails 均已存在。
- `migrations/031` 權限已是 `644`
- `app.py``SYSTEM_VERSION` 已從 `config.py` importapp 內只留版本註解。
- V2 提到的 `app.py` 死 import 與 `scheduler.py import schedule` 已不成立;`app.py` 仍使用 `schedule.run_pending()` 等呼叫。
- `tests/test_phase3f_cleanup_contracts.py` 已補 guardV2 點名的舊 app imports 不得回來,且 `app.py` 的 active `schedule` 用法不可被誤刪。
- V2 點名的 3 個 silent failure 點位已不是 `except: pass`OpenClaw 趨勢圖暫存檔清理與 Notification public_url 讀取失敗都會記 log並由 `tests/test_phase3f_cleanup_contracts.py` 守住。
- Cron 盲區清單多數已補 `_notify_scheduler_failure()`ROI 月報已避開 09:00 改 09:05AI smoke 已是 09:10。
- V2 指出的 9 個 cron 盲區已補回歸守門8 個 `run_scheduler.py` wrapper 必須呼叫 `_notify_scheduler_failure()``scheduler.py::run_promo_event_task` 必須呼叫 `notify_failure()`
- 09:00 排程衝突已有回歸守門:`daily_report=09:00``roi_monthly_report=09:05``ai_smoke_daily_summary=09:10` 必須保持錯開。
- AutoHeal inline host transition 告警已有 DB transition dedup 守門:`run_host_health_probe()` 只在健康狀態翻轉且 1h 內沒有同方向 transition 時推送。
- CD migration 全範圍冪等已有回歸守門:`.gitea/workflows/cd.yaml` 必須維持 024-099 pattern、`sort | uniq``for m in $V5_MIGRATIONS` apply loop。
- CD Observability production smoke 已補 timeout 守門:`quick_review.sh --observability-smoke` 必須帶 `--timeout 12`
- 0-byte `database/momo*.db` 迷惑檔已不存在;真實 SQLite 僅在 `data/momo_database.db`
- `.gitignore` 已涵蓋 `.claude/worktrees/``.tmp_*``tmp_*.png``MOMO Pro/`、root/uploads/screenshots 與 `MOMO Pro` uploads/screenshots並由 `tests/test_gitignore_contracts.py` 守住。
- `cache_service.py` 已成為 `cache_manager.py` 的相容 shim`_SALES_CACHE_TTL` 單一來源有測試鎖住。
- `aiops-core/requirements.txt` 已不存在,`aiops-core/README.md` 已標記此目錄只保留歷史 stub不應安裝或部署。
- V2 提到的「死依賴」不可整批刪:`beautifulsoup4` 用於多個 crawler、`google-api-python-client` 用於 Google Drive、`google-generativeai` 用於 Gemini paths、`python-pptx` 用於 PPT generator、`matplotlib` 用於 Telegram/圖表/PPT。
- `tests/test_requirements_pinning.py` 已鎖住上述被 V2 誤列的 runtime dependencies套件需留在 `requirements.txt`,且至少一個 runtime import 證據仍存在。
- `paramiko` 已確認沒有 runtime importADR-013 現行實作改以 `utils/ssh_helper.py` 組 CLI `ssh`,因此已從 `requirements.txt` 移除並補測試防止依賴殘影回來。
- `pgvector` Python package 與 `matplotlib-inline` 已確認不是 runtime 依賴pgvector 走 PostgreSQL extension + 本地 SQLAlchemy `Vector` typeJupyter inline backend 不屬 production path兩者已從 `requirements.txt` 移除並補測試。
- `tests/test_pg_sync.py` 已改為 opt-in integration test預設不再連 localhost PostgreSQL 或建立/刪除測試表,需 `RUN_PG_SYNC_INTEGRATION=1` 且提供 `POSTGRES_PASSWORD` 才執行。
- `services/pg_sync_service.py` 是顯式 opt-in legacy CLI不是生產自動同步路徑`tests/test_pg_sync_contract.py` 已守住預設 OFF 與 runtime paths 不自動 import。
- `qwen3:14b` 不是未使用 Ollama 模型OpenClaw QA、NemoTron dispatch 與 LLM model router 仍有現役路徑;`tests/test_qwen3_runtime_usage.py` 已守住,不能只因體積大就三主機移除。
- Ollama host env 已加白名單護欄:`OLLAMA_HOST*` / `EMBEDDING_HOST` 只接受 GCP-A、GCP-B、111 或 110 proxy誤設 188/localhost 會回到核准主機。
- Hermes intent 與批量 analyst 已從單次 `resolve_ollama_host()` + raw `requests.post('/api/generate')` 改為 `OllamaService.generate()`,同一請求會依序 retry GCP-A → GCP-B → 111並保留 `HERMES_KEEP_ALIVE` 與實際 provider 回寫測試。
- NemoTron qwen3 dispatch 的 `/api/chat` tool-calling 路徑已補同一請求三主機 retryhost 失敗會 `mark_unhealthy()` 後再 resolve 下一台GCP-A 失敗可在同次 dispatch 接 GCP-B/111三台都失敗才 fallback NIM。
- PPT vision、PPT 文案 final fallback 與 MCP 離線 final fallback 已改走 `OllamaService.generate()``OllamaService.generate()` 支援 `options``keep_alive` 與 vision `images`,特殊 `/api/generate` 路徑同樣取得三主機 retry。
- OpenClaw QA / daily Hermes template / NemoTron qwen3 的 flag 文件與測試已對齊 Ollama-first 預設 ON顯式 `false` 才是 Gemini/NIM legacy 緊急退路。OpenClaw QA 已移除單一 `OPENCLAW_QA_OLLAMA_HOST` 主機覆寫,`_call_qwen3_qa()` 改走 `OllamaService` 的 GCP-A → GCP-B → 111 retry 並回寫實際 provider。
- Code Review pipeline 已對齊 Ollama-first`_hermes_scan()``_openclaw_assess()` 都先走 `OllamaService` 的 GCP-A → GCP-B → 111 retryGemini 僅在 Ollama與可選 Claude失敗後以 `code_review_openclaw_gemini` caller 記錄備援,不再以 `code_review_openclaw` 直接 Gemini-first。
- Telegram 圖片商品辨識已對齊 Ollama-first`routes/openclaw_bot_routes.py` 會先用 `OPENCLAW_IMAGE_VISION_MODEL` 透過 `OllamaService` retry GCP-A → GCP-B → 111Gemini 只以 `openclaw_bot_image_gemini` caller 作為圖片辨識備援。
- `.env.example` 已補齊 Python runtime 實際讀取的環境變數,`tests/test_phase3f_cleanup_contracts.py::test_env_example_documents_runtime_os_env_keys` 會掃 `app.py/config.py/scheduler.py/run_scheduler.py/routes/services/utils``os.getenv()` / `os.environ.get()`;只允許 `PYTEST_CURRENT_TEST``MOMO_ALLOW_INSECURE_CONFIG_FOR_TESTS` 兩個測試內部 key 不進範例。
- `docker-compose*.yml` 使用的 `${VAR}` 也已納入 `.env.example` 契約,包含 MCP compose 的 `TAVILY_API_KEY``EXA_API_KEY``MCP_POSTGRES_PASSWORD``FIRECRAWL_AUTH_KEY`,以及 image tag / Grafana / pgAdmin / Metabase / Grist 變數;`test_env_example_documents_docker_compose_variables` 會守住。
- Market Intel `seed_writer_cli_status` route 已補 API 層回歸:即使 `execute=true` 且環境有 `MARKET_INTEL_SEED_WRITE_APPROVAL`API 仍不得回吐 token / `approval_token_hint` / 固定 token 文案,且不得 ready 或寫入;`tests/test_market_intel_skeleton.py::test_seed_writer_cli_status_route_never_leaks_approval_token` 會守住。
- Docker 主 compose 的 `momo-app` / `scheduler` / `telegram-bot` 已有 `mem_limit``healthcheck`,並由 `tests/test_docker_compose_runtime_mounts.py` 守住V2 提到的 nginx / nginx-monitor / metabase / grist healthcheck 缺口需先看 profiles這些服務分別被鎖在 `local-dev``deprecated``bi`,不是 default production path。
- MCP compose 安全邊界已有 `tests/test_mcp_compose_contracts.py`postgres/omnisearch/firecrawl healthcheck、Firecrawl/Playwright/Redis/filesystem memory guardrails、filesystem-mcp read-only mount 與不接 docker socket 都會被測試守住。
- `_navbar.html` 已移除 V1 點名的 `--momo-legacy-accent` 與舊 hex `#d96f52/#a95846/#9f4f3e`,改用 `--momo-nav-accent*``--momo-page-accent*` warm tokens`tests/test_frontend_v2_assets.py::test_legacy_navbar_uses_warm_token_accent_aliases` 會守住。
- `routes/price_comparison_routes.py` 的 MOMO crawler TODO 已接到既有 `services.momo_crawler.search_momo_products()`;未手動上傳 MOMO 商品時會自動抓 MOMO再交給比價服務。
- 未引用的根層 `templates/list.html` Phase 4 placeholder 已刪除,真實缺貨清單 route 使用 `vendor_stockout_list_v2.html`(或 `ui=legacy` 時的 `vendor_stockout/list.html``tests/test_phase3f_cleanup_contracts.py` 會防止根層 placeholder 回來。
- AI 觀測台 V3 排版規範已補強:`scripts/check_responsive_overflow.js` 會把視覺 overflow offenders 視為失敗,並允許表格/圖表在 `.obs-table-shell``.obs-chart-frame` 等局部容器內滾動;`observability-system.css` / `web/static/css/observability-system.css` 已同步新增 bounded table/chart/mobile containmentCSS mirror 與 `quick_review.sh --observability-qa --skip-production` 均通過。
- app.py/BP 路由雙寫已完成收斂active `@app.route` 為 0`USE_MODULAR_ROUTES` 與舊 routes registry shim 已不存在;`tests/test_phase3f_cleanup_contracts.py::test_app_py_stays_blueprint_only_for_routes` 會防止 route decorator 回到 `app.py`
- `app.py` 開頭的歷史「重開機後請依序執行」TODO banner 已移除;入口治理以 `AGENTS.md` / `CONSTITUTION.md` / ADR / memory 索引為準,`tests/test_phase3f_cleanup_contracts.py::test_app_py_does_not_start_with_stale_restart_todo_banner` 會防止 stale 操作清單回流。
- `docs/guides/devops_handbook.md` 已移除活躍手冊中的舊 K8s command 區塊,並把 app 操作改為 Gunicorn HUP 熱重載、Docker Compose 精準 force-recreate、`momo-app` service build`tests/test_phase3f_cleanup_contracts.py::test_devops_handbook_uses_current_docker_runtime_commands` 會防止 `kubectl``docker restart momo-pro-system` 與錯誤 compose service name 回流。
- `/cicd` legacy dashboard 已停用舊叢集副作用rollback 會回 410`restart_pods` action 會被拒絕diagnosis 不再 SSH 執行叢集探測;`tests/test_cicd_legacy_cluster_disabled.py` 會防止 `kubectl` / rollout command 回到 `routes/cicd_routes.py`
- AI 觀測台 badge/chip 對比規範已補強:`.momo-observability-mode` 內的 badge、pill 與 nested surface 會改走亮底、8px radius、無負字距、可換行且不再殘留低對比 legacy dark-hero 樣式CSS mirror、`quick_review.sh --observability-ui``quick_review.sh --observability-qa --skip-production` 均通過。
- AI 觀測台 rendered visual contract 已入庫:`scripts/check_observability_visual_contract.sh` 會用 Playwright 檢查 10 頁 × desktop/tablet/mobile 的 title typography、surface radius/background、chip contrast、hero height 與水平 overflowV10.116 main 版 local server 驗證 30 項 PASS。測未部署變更時必須帶 localhost `--base-url`,打 production fail 可能只是正式站尚未部署該版。
- V10.117 已把 AI 觀測台背景語彙收斂為 tokenized dot-matrix合約會要求 hero/signal/panel surface 的 computed `background-image``radial-gradient`,並拒絕 legacy `linear-gradient` / `background-image: none` 回流;終端 dot-matrix layer 必須留在 CSS 檔尾以贏過舊 neutralizer。
- `/observability/host_health` 在 SQLite local QA 下已略過 `host_health_probes` persistence避免 BIGINT autoincrement drift 造成 warning正式 Postgres session 仍維持 probe history 寫入,`tests/test_admin_observability_routes.py::test_host_health_skips_probe_persistence_on_sqlite` 會守住。
- Telegram `momo:eig:<event_id>` callback 已在 `routes/openclaw_bot_routes.py``services/telegram_bot_service.py` 實作並有 webhook 測試覆蓋,不是未實作缺口。
- Telegram `date_*` / `goal_*` 不是死 callback handler按鈕先送 `await:*` 進入輸入等待狀態,使用者下一則文字才由 pending action 消費;`tests/test_openclaw_bot_menu_keyboards.py``tests/test_openclaw_bot_routes_webhook.py` 已覆蓋。
- `services/ai_automation_smoke_service.py` 不是死 service`run_scheduler.py` 每日 09:10 掛 `run_ai_smoke_daily_summary_task()`,該 task 會呼叫 `send_smoke_daily_summary()``tests/test_ai_automation_smoke_service.py``tests/test_ai_automation_metrics.py` 已覆蓋。
- `mcp_calls.status` CHECK 已接受 `ok/error/timeout/rate_limited/cache_only`,與 `services/mcp_router.py` 的細分狀態一致。
- DB migration / ORM 覆蓋已有 `tests/test_migration_metadata_coverage.py` 守門,`Base.metadata.tables - migrations CREATE TABLE` 必須為空;`tests/test_ai_observability_models.py` 也鎖住 v5 observability ORM stub。
- V2 BLOCKED migration 守門已補:`031-037` 必須存在且 group/world-readable`database/momo.db` / `momo_data.db` / `momo_database.db` 迷惑檔不得回來。
- `host_health_probes.chk_host_label_029` 不一致已有 migration 033 修補並補測試:必須重建 CHECK且接受 `GCP-SSD``GCP-SSD-2``111 備援` 與兩個 110 Nginx proxy runtime labels。
- `rag_query_log` / `learning_episodes``embedding_signature` 已由 migration 034、ORM 欄位、RAG/learning 寫入路徑與 migration metadata 測試覆蓋。
- `incidents` 雙欄相容與 `action_plans` source/status guardrails 已在 migration 036/037、migration metadata 測試與 `tests/test_auto_heal_safety.py` 覆蓋。
- `services/agent_actions.py` 不是死碼:`services/event_router.py` 透過 `SAFE_ACTIONS` registry 動態執行 ADR-012 L2 actions`tests/test_agent_actions.py` 已鎖住 L2 `SAFE_ACTIONS` 與 L3 `OPS_ACTIONS` 邊界,防止 HITL ops 動作誤進自動白名單。
## 不可盲動
- `services/agent_actions.py` 不能只看靜態 caller 清理;已確認它是 `SAFE_ACTIONS` 動態 dispatch 入口,未來改動必須同步更新 registry 與 EventRouter 測試。
- `logo_circle.svg` / `logo_navbar.svg` / `logo_transparent.png` 不能只因 runtime `rg` 無引用就刪;設計文件仍規劃品牌頁、登入頁、錯誤頁使用。
- 多個永遠 OFF feature flag 屬產品/上線策略決策,不應在清債時直接全部改 ON 或刪除。
- `ai_calls.rag_hit` 不等同 `rag_query_log.saved_call`:跳過 LLM 的 RAG 命中應記在 `rag_query_log.saved_call`;有實際 LLM 呼叫且 caller 明確用了 RAG context 時才適合標 `ai_calls.rag_hit`
## 本輪已推 commits
- `36d0e5d` 標記 RAG 命中節省 LLM 呼叫
- `20cab6e` 補上 RAG hit logger 回歸測試
- `6817f64` 移除舊 SSH jump 設定殘影
- `44eb369` 補上 MCP filesystem 唯讀白名單
- `2068a37` 修正 Telegram 分類按鈕預設 callback
- `bdb74b1` 告警 BGE embedding 一致性異常
- `d15b221` 細分 MCP 呼叫遙測狀態
- `34db2db` 修正 scheduler 合成告警 trace
- `5785a58` 補齊 scheduler 觀測任務失敗告警
- `a335ab5` 修正 AutoHeal Telegram 觸發者審計
- `d7ae243` 清空 Telegram webhook 使用者上下文
- `ba8510e` 補齊 MCP 早退狀態
- `317ff1b` 共用匯入檔名日期解析
- `c300e49` 記錄 ROI 月報反饋區塊失敗
- `f49413e` 記錄 EA short-circuit 遙測失敗
- `0a75d11` 記錄 Claude 成本節流檢查失敗
- `5625032` 記錄 AI caller registry 匯入失敗
- `0bc6f18` 更新 Claude 盤點修補記憶
- `3cb091f` 記錄 Observability fail-safe 區塊失敗
- `e29529f` 校正 Observability 修補記憶 hash
- `4e6e9bf` 綁定自動匯入日期查詢參數
- `47c59fd` 更新自動匯入修補記憶
- `ae79cdd` 記錄依賴盤點驗證結果
- `2b1174a` 移出誤入的本地變更
- `adfcccf` 補齊盤點修補 commit 清單
- `4256a04` 記錄 Telegram 與 MCP 缺口驗證
- `5285abe` 記錄 DB migration 覆蓋守門
- `f9d3da5` 記錄 AutoHeal DB guardrail 驗證
- `7e92850` 記錄 Agent Actions 動態入口驗證
- `89c400d` 補上 OpenClaw best-effort 區塊紀錄
- `ec5a22d` 記錄 Telegram pending action 驗證
- `f44c429` 補強 AI logger best-effort 診斷
- `8a36856` 補強 Telegram callback 診斷
- `5b52af9` 補強 cache best-effort 診斷
- `497c376` 記錄 AI smoke service 入口驗證
- `b22cbb2` 守住 scheduler 失敗告警覆蓋
- `8026b93` 守住 scheduler 早晨排程錯開
- `eb6886e` 同步 scheduler 排程摘要
- `b24241f` 守住 migration blocker 修補
- `6c86839` 守住盤點誤判依賴
- `2e2b775` 守住 V2 import 清理狀態
- `58ba95b` 守住月結匯入 append 路徑
- `4079f1c` 守住 CD migration 全範圍執行
- `81aa424` 守住 Observability smoke timeout
- `dc99bab` 移出誤入的本地變更
- `546c63f` 守住 V2 silent failure 修補
- `c165081` 守住 host label migration 對齊
- `4921275` 守住 RAG embedding signature migration
- `035b88c` 守住 AutoHeal migration guardrails
- `5b6b35f` 守住 AutoHeal inline 告警去重
- `749eace` 移除未使用 Paramiko 依賴
- `3c65034` 移除未使用 runtime 依賴
## 後續補推 commits3c65034 之後)
- `2ac751f` 補齊盤點修補 commit 清單
- `6c236eb` 快取當日業績頁面內容
- `0d68f3e` 快取商品看板比價總覽
- `c306fb6` 隔離 PG sync 整合測試
- `8099bb6` 守住 qwen3 現役模型路徑
- `49c576b` 標定 PG sync 為 opt-in 工具
- `1aeb4a4` 移除 AI logger 未用 stack 推斷
- `d02b712` 標明 cache service 相容角色
- `72daa53` 快取業績分析頁面資料
- `8b5a4a3` 接上 MOMO 自動比價爬蟲
- `5942e39` 守住本機產物忽略規則
- `ce20892` 限制 Ollama host 只能走核准節點
- `6313fdd` 對齊 Ollama-first flag 語義
- `d6e8a4f` 忽略本地截圖暫存檔
- `0c9f927` 啟用 Market Intel seed writer CLI gate
- `2130c4f` 守住 AI provider Ollama-first
- `b65a319` 固化 Ollama 三主機路由紅線
- `0380d4c` 接上 responsive overflow quick review
- `86fc9c9` 避免商品看板冷快取阻塞
- `ec93d09` 收緊模組化治理掃描範圍
- `b2ab03f` 入庫 responsive overflow guard 腳本
- `5ee7fd9` 忽略未確認設計審計 dump
- `f8b9b1a` 共用業績分析頁面快取
- `d384c35` 快取業績分析頁面 context
- `d8c7f6f` 快取當日業績頁面 context
- `2f67e16` 共用當日業績頁面快取
- `ab612cb` 補 OpenClaw 選單複核報告
- `c78bb1d` 記錄 Market Intel 正式端只讀複核
- `9ec7713` 補 AiderHeal 靜默失敗診斷
- `28c9555` 修正挑品 Agent SQLite fallback
- `c227bb4` 補競品 Feeder 搜尋詞 fallback 診斷
- `dd8ccdf` 共用業績分析引導頁快取
- `e8497d0` 補業績分析引導頁快取測試
- `f4883b4` 保留 PPT Vision 主機標記失敗診斷
- `bff8c49` 補 Code Review 失敗通知診斷
- `0bdb993` 補 OpenClaw 報表資料解析診斷
- `25e0570` 補齊 AI runtime 環境範例
- `2b2233d` 補齊 OpenClaw 與 DeepSeek 環境範例
- `acef0fa` 守住 runtime 環境變數文件契約
- `ae1895f` 守住 compose 環境變數文件契約
- `73bbc45` 更新 Claude 盤點驗證記憶
- `490336a` 守住 Market Intel seed token 不外洩
- `dc6fc69` 守住核心容器資源與健康檢查
- `7766e35` 守住 MCP compose 安全邊界
- `621c9f2` 守住 optional compose profile 邊界
- `353295a` 移除舊 Navbar accent 色票殘影
- `ca97840` 守住 Agent Actions 動態白名單邊界
- `ba140f1` 移除未引用缺貨清單佔位模板
- `9af9592` 修正 AI 觀測台 V3 排版規範
- `a305b26` 記錄觀測台 V3 排版守門
- `830661b` 守住 app.py 不再新增路由
- `c50180f` 補齊 AI 觀測台 badge 對比規範
- `b7ba54a` 更新 ADR-017 模組化現況
- `b6e6573` 收斂觀測台手機字體與視覺契約
- `c10e6a4` 記錄觀測台視覺契約守門
- `5a21e23` 略過 SQLite host probe 寫入
- `f947469` 融合觀測台點陣視覺語彙
- `60b73e1` 固定觀測台點陣層覆蓋順序

View File

@@ -1,45 +1,135 @@
# 程式碼模組化盤點2026-04-30
# 程式碼模組化盤點2026-04-302026-05-13 校正
> 用途:接續 ADR-017 Phase 3f 時,快速知道哪些 Python 檔案仍是大檔技術債,以及新增功能應該放在哪個模組層。
## 盤點結論
- Python 總量:約 66,997 行
- 最大壓力區:`routes/`21,095 行、`services/`26,023 行。
- `app.py` 目前約 1,209 行,功能定位應固定為 bootstrap / Blueprint registration / startup guard不再承接新 route。
- 目前工作樹仍有 16 個 Python 檔案超過 800 行;這些不是禁止修 bug而是禁止繼續塞新功能。
- Python 總量:約 139,476 行(排除 `venv/``backups/``__pycache__/``.claude/worktrees/`
- 最大壓力區:`services/`84,159 行、`routes/`36,245 行。
- `app.py` 目前約 1,232 行,功能定位應固定為 bootstrap / Blueprint registration / startup guard不再承接新 route。
- 目前工作樹仍有 33 個 Python 檔案達到或超過 800 行;這些不是禁止修 bug而是禁止繼續塞新功能。
- 2026-05-05 追記Phase 38→56 觀測台戰役讓 `routes/admin_observability_routes.py``run_scheduler.py` 進入大檔治理清單;後續觀測台功能應先抽 query/action service不再把新 SQL 與 L2 mutation 直接塞回 route。
- 2026-05-06 追記跨平台市場情報模組啟動前必須先把新增爬蟲、排程、DB schema、UI route 全部隔離在 `market_*` / `services/market_intel/` / `routes/market_intel_routes.py`,不可塞回既有大檔。
- 2026-05-18 追記Phase 42 市場情報只在 `app.py``EXPECTED_METADATA_TABLES` 補上 `market_alert_review_queue` 名稱,未新增 route / bootstrap 邏輯;後續仍應把 metadata verification 抽到 app factory 或 startup guard module避免 `app.py` 繼續承接功能。
- 2026-05-19 追記:同步治理測試盤點,校正 `routes/admin_observability_routes.py` 行數;此處只更新 inventory不變更觀測台功能。
- 2026-05-19 追記V10.229 之後 `services/ppt_vision_service.py` 進入 800 行治理清單;本次只補 inventory 讓守門測試反映現況,不變更 PPT 視覺 QA 功能。
- 2026-05-24 追記:同步 V10.460 ElephantAlpha decision_envelope helper 後的 `services/elephant_alpha_autonomous_engine.py` 行數;此處只更新 inventory不變更 AI engine 行為。
- 2026-05-19 追記:同步背景 V10.276 ElephantAlpha 更新後的 `services/elephant_alpha_autonomous_engine.py` 行數;此處只更新 inventory不變更 AI engine 行為。
- 2026-05-19 追記:同步背景 V10.281/V10.282 dashboard 與 Code Review pipeline 更新後的行數;此處只更新 inventory不變更 dashboard 或 code review 行為。
- 2026-05-19 追記:同步背景 PChome identity 價格刷新與競品風險查詢更新後的 `services/competitor_price_feeder.py` 行數;此處只更新 inventory不變更 feeder 行為。
- 2026-05-19 追記:同步背景 Telegram 模板擴充後的 `services/telegram_templates.py` 行數;此處只更新 inventory不變更 Telegram 格式化行為。
- 2026-05-20 追記:同步背景 PChome unit-comparable identity 更新後的 `services/marketplace_product_matcher.py` 行數;此處只更新 inventory不變更商品比對行為。
- 2026-05-20 追記:同步背景商品看板覆核快取回填後的 `services/competitor_intel_repository.py` 行數;此處只更新 inventory不變更競品情報 repository 行為。
- 2026-05-20 追記:同步背景商品看板比價覆核狀態分流後的 `routes/dashboard_routes.py` 行數;此處只更新 inventory不變更 dashboard 行為。
- 2026-05-20 追記:同步背景匯出流程更新後的 `routes/export_routes.py` 行數;此處只更新 inventory不變更 export 行為。
- 2026-05-20 追記:同步背景 PChome feeder 人工覆核回饋採納後的 `services/competitor_price_feeder.py` 行數;此處只更新 inventory不變更 feeder 行為。
- 2026-05-20 追記:同步背景 PChome 比價人工覆核閉環後的 `services/competitor_intel_repository.py` 行數;此處只更新 inventory不變更競品情報 repository 行為。
- 2026-05-20 追記:同步背景 PChome identity / price direction 更新後的 `services/marketplace_product_matcher.py` 行數;此處只更新 inventory不變更商品比對行為。
- 2026-05-20 追記:同步背景 PChome crawler 搜尋韌性擴充後的 `services/pchome_crawler.py` 行數;此處只更新 inventory不變更 PChome crawler 行為。
- 2026-05-20 追記:同步 PChome 近門檻候選重評與 matcher 系列/刀片數防錯配更新後的 `services/marketplace_product_matcher.py``services/competitor_price_feeder.py` 行數;此處只更新 inventory不變更比價行為。
- 2026-05-20 追記:同步 PChome 搜尋詞品質層、候選召回與 hard-veto 狀態分流更新後的 `services/marketplace_product_matcher.py``services/competitor_price_feeder.py` 行數;並補列背景市場情報 deployment readiness 大檔,僅更新 inventory。
- 2026-05-20 追記:同步 PChome 搜尋詞特定品線優先級更新後的 `services/marketplace_product_matcher.py` 行數;此處只更新 inventory不變更模組化決策。
- 2026-05-20 追記:同步 PChome 共享 identity anchor scorer 與市場情報 review report route 進入大檔門檻後的行數;此處只更新 inventory不變更功能。
- 2026-05-20 追記:同步 PChome contained identity anchor scorer 更新後的 `services/marketplace_product_matcher.py` 行數;此處只更新 inventory不變更模組化決策。
- 2026-05-20 追記:同步 PChome spec/name alignment near-threshold scorer 更新後的 `services/marketplace_product_matcher.py` 行數;此處只更新 inventory不變更模組化決策。
- 2026-05-20 追記:同步市場情報 review report route 與 review receipt 巨檔現況,並校正 PChome fresh-search recovery 更新後的 `services/competitor_price_feeder.py``services/marketplace_product_matcher.py` 行數;此處只更新 inventory不變更模組化決策。
- 2026-05-21 追記:同步 Browse.sh 診斷導入、PChome 變體搜尋與色號防錯配更新後的 `services/marketplace_product_matcher.py` 行數,並校正市場情報 review report route 目前行數;此處只更新 inventory不變更模組化決策。
- 2026-05-21 追記:同步市場情報 MCP runtime smoke receipt gate 後的 `routes/market_intel_routes.py``services/market_intel/deployment_readiness.py` 行數;本次 route 只承接既有 Blueprint glue後續新增 MCP/UI gate 應優先拆出子 Blueprint 或 route registration helper。
- 2026-05-21 追記:同步 111 fallback context/resource guard 合併後的 `services/ollama_service.py` 行數;此處只更新 inventory不變更 Ollama 路由行為。
- 2026-05-21 追記:同步專業比價分級連動合併後的 `services/competitor_intel_repository.py``services/nemoton_dispatcher_service.py` 行數;此處只更新 inventory不變更比價或告警行為。
- 2026-05-21 追記:同步市場情報 MCP runtime promotion gate 後的 `routes/market_intel_routes.py``services/market_intel/deployment_readiness.py` 行數;此處只更新 inventory後續市場情報 MCP route 應拆出子 Blueprint。
- 2026-05-24 追記:同步市場情報 MCP manual fetch handoff gate 後的 `routes/market_intel_routes.py``services/market_intel/deployment_readiness.py` 行數;本次新增邏輯已放在獨立 `services/market_intel/mcp_manual_fetch_handoff.py`route 僅保留薄 glue下一個 MCP/UI gate 應優先拆出子 Blueprint 或 route registration helper。
- 2026-05-24 追記:同步市場情報 MCP fetch target review gate 後的 `routes/market_intel_routes.py``services/market_intel/deployment_readiness.py` 行數;本次新增邏輯已放在獨立 `services/market_intel/mcp_fetch_target_review.py`route 僅保留薄 glue後續市場情報 MCP route 應拆出子 Blueprint 或 route registration helper。
- 2026-05-24 追記:同步市場情報 MCP fetch run package gate 後的 `routes/market_intel_routes.py``services/market_intel/deployment_readiness.py` 行數;本次新增 endpoint 已拆到 `routes/market_intel_mcp_run_routes.py`,主 Blueprint 只新增 extension import後續 MCP route 應延續此模式。
- 2026-05-24 追記:同步市場情報 MCP fetch run readiness gate 後的 `services/market_intel/deployment_readiness.py` 行數;本次新增 endpoint 延續 `routes/market_intel_mcp_run_routes.py` route extension新增邏輯放在獨立 `services/market_intel/mcp_fetch_run_readiness.py`
- 2026-05-31 追記:同步市場情報 MCP fetch candidate queue review gate 後的 `services/market_intel/deployment_readiness.py` 行數;本次新增邏輯維持在獨立 `services/market_intel/mcp_fetch_candidate_queue_review.py`route 延續 `routes/market_intel_mcp_run_routes.py` extension。
- 2026-05-31 追記:同步市場情報 MCP fetch candidate queue writer preflight gate 後的 `services/market_intel/deployment_readiness.py` 行數;本次新增邏輯維持在獨立 `services/market_intel/mcp_fetch_candidate_queue_writer_preflight.py`route 延續 `routes/market_intel_mcp_run_routes.py` extension。
- 2026-05-31 追記:`services/market_intel/mcp_fetch_candidate_queue_writer_preflight.py` 目前 628 行,略過 600 行提醒門檻;暫不拆分的理由是 gate 條件、sample payload 與 side-effect blocklist 需留在單一 preview module 便於審核,下一個 writer CLI review gate 若共用相同常數再抽 `mcp_fetch_candidate_queue_writer_policy.py`
- 2026-05-31 追記:同步市場情報 MCP fetch candidate queue writer CLI review gate 後的 `services/market_intel/deployment_readiness.py` 行數;本次新增 `services/market_intel/mcp_fetch_candidate_queue_writer_cli_review.py` 為 591 行,仍低於 600 行提醒門檻。
- 2026-05-31 追記:同步市場情報 MCP fetch candidate queue writer run package review gate 後的 `services/market_intel/deployment_readiness.py` 行數;本次新增 `services/market_intel/mcp_fetch_candidate_queue_writer_run_package_review.py` 為 660 行,略過 600 行提醒門檻。暫不拆分的理由是 run package gate 需要把 CLI review linkage、artifact manifest、operator shell command sequence 與 side-effect blocklist 放在單一 preview module 便於安全審核;若下一段 run readiness review 重複相同 policy應抽出 writer policy helper。
- 2026-05-31 追記:同步市場情報 MCP fetch candidate queue writer run readiness gate 後的 `services/market_intel/deployment_readiness.py` 行數;本次新增 `services/market_intel/mcp_fetch_candidate_queue_writer_run_readiness.py` 為 640 行,略過 600 行提醒門檻。暫不拆分的理由是 readiness gate 需同時審核上一段 run package review linkage、operator artifact path policy、CLI-only/token-only confirmation 與 side-effect blocklist若後續 run receipt gate 再重複 policy應抽出 `mcp_fetch_candidate_queue_writer_policy.py`
- 2026-05-31 追記:同步市場情報 MCP fetch candidate queue writer run receipt review gate 後的 `services/market_intel/deployment_readiness.py` 行數;本次新增 `services/market_intel/mcp_fetch_candidate_queue_writer_run_receipt_review.py` 為 688 行,略過 600 行提醒門檻。暫不拆分的理由是 receipt gate 需同時審核 readiness linkage、receipt identity、artifact path policy、operator confirmation、token redaction 與 side-effect blocklist若下一段 closeout gate 重複相同 path/side-effect policy應抽出 `mcp_fetch_candidate_queue_writer_policy.py`
- 2026-05-31 追記:同步市場情報 MCP fetch candidate queue writer run closeout review gate 後的 `services/market_intel/deployment_readiness.py` 行數;本次新增 `services/market_intel/mcp_fetch_candidate_queue_writer_run_closeout_review.py` 為 724 行,略過 600 行提醒門檻。暫不拆分的理由是 closeout gate 需同時審核 receipt review linkage、artifact manifest preservation、rollback note、read-only inventory next-step、lightweight preview sample 與 side-effect blocklist若下一段 post-closeout inventory gate 重複 path/side-effect policy應抽出 `mcp_fetch_candidate_queue_writer_policy.py`
- 2026-05-31 追記:同步市場情報 MCP fetch candidate queue writer post-closeout inventory review gate 後的 `services/market_intel/deployment_readiness.py` 行數;本次新增 `services/market_intel/mcp_fetch_candidate_queue_writer_post_closeout_inventory_review.py` 為 649 行,略過 600 行提醒門檻。暫不拆分的理由是 inventory gate 需同時審核 closeout linkage、read-only inventory 摘要、artifact path policy、operator boundary confirmation 與 side-effect blocklist後續若 candidate queue review handoff 再複用同一套 path/side-effect policy應抽出 `mcp_fetch_candidate_queue_writer_policy.py`
- 2026-05-31 追記:同步市場情報 MCP fetch candidate queue writer review handoff gate 後的 `services/market_intel/deployment_readiness.py` 行數;本次將 sample payload 抽到 `services/market_intel/mcp_fetch_candidate_queue_writer_review_handoff_sample.py`105 行),主 gate `services/market_intel/mcp_fetch_candidate_queue_writer_review_handoff.py` 降為 571 行,低於 600 行提醒門檻;後續若 candidate queue review inventory 繼續複用 path/side-effect policy應抽出 `mcp_fetch_candidate_queue_writer_policy.py`
- 2026-05-31 追記:同步市場情報 MCP fetch candidate queue writer review inventory gate 後的 `services/market_intel/deployment_readiness.py` 行數;本次新增 `services/market_intel/mcp_fetch_candidate_queue_writer_review_inventory.py`462 行)、`services/market_intel/mcp_fetch_candidate_queue_writer_review_inventory_gates.py`183 行)與 `services/market_intel/mcp_fetch_candidate_queue_writer_review_inventory_sample.py`107 行),全部低於 600 行提醒門檻;`routes/market_intel_mcp_run_routes.py` 目前 717 行,仍低於 800 行但後續新增 MCP gate 應持續評估拆第二個 route extension。
- 2026-05-31 追記:同步市場情報 MCP fetch candidate queue writer review decision gate 後的 `services/market_intel/deployment_readiness.py` 行數;本次新增 `services/market_intel/mcp_fetch_candidate_queue_writer_review_decision.py`498 行)、`services/market_intel/mcp_fetch_candidate_queue_writer_review_decision_gates.py`241 行)與 `services/market_intel/mcp_fetch_candidate_queue_writer_review_decision_sample.py`118 行),全部低於 600 行提醒門檻;`routes/market_intel_mcp_run_routes.py` 目前 772 行,仍低於 800 行但已接近門檻,下一段 MCP route 應優先拆第二個 route extension。
- 2026-05-31 追記:同步市場情報 MCP fetch candidate queue writer review decision approval gate 後的 `services/market_intel/deployment_readiness.py` 行數;本次新增 `services/market_intel/mcp_fetch_candidate_queue_writer_review_decision_approval.py`560 行)、`services/market_intel/mcp_fetch_candidate_queue_writer_review_decision_approval_gates.py`255 行)、`services/market_intel/mcp_fetch_candidate_queue_writer_review_decision_approval_sample.py`140 行)與 `routes/market_intel_mcp_review_routes.py`64 行),全部低於 600 行提醒門檻;`routes/market_intel_mcp_run_routes.py` 維持 770 行,本次未再加 endpoint改以第二個 MCP review route extension 承接。
- 2026-06-01 追記:同步市場情報 Professional Source Governance gate 後的 `services/market_intel/deployment_readiness.py` 行數;本次新增 `services/market_intel/mcp_professional_source_governance.py`391 行)、`services/market_intel/mcp_professional_source_governance_gates.py`266 行)、`services/market_intel/mcp_professional_source_governance_sample.py`175 行)與 `routes/market_intel_mcp_review_routes.py`165 行),全部低於 600 行提醒門檻;`services/market_intel/deployment_readiness.py` 仍是既有 P2 大檔,只加 preview-safe check 與 smoke target後續需延續小 service + route extension 模式。
- 2026-06-03 追記:新增 `services/market_intel/mcp_fetch_target_source_governance_review.py`237 行),並將 `mcp_professional_source_governance_sample.py` 擴為 307 行、`routes/market_intel_mcp_review_routes.py` 擴為 207 行;新增服務仍低於 600 行提醒門檻。`services/market_intel/deployment_readiness.py` 擴為 2010 行,仍屬既有 P2 大檔,後續應優先拆 readiness smoke/check registration。
- 2026-05-24 追記:同步背景 Code Review 111 fallback 保護合併後的 `services/code_review_pipeline_service.py` 行數;此處只更新 inventory不變更 Code Review 行為。
- 2026-05-21 追記:同步 PChome/LUDEYA 商品線名稱漂移比對更新後的 `services/marketplace_product_matcher.py` 行數;此處只更新 inventory不變更模組化決策。
- 2026-05-21 追記:同步 MAC/Yuskin/AHC 名稱漂移與 bundle equivalent matcher 更新後的 `services/marketplace_product_matcher.py` 行數;此處只更新 inventory不變更模組化決策。
- 2026-05-21 追記:同步 EDM 失效頁 alert guard 與 REJURAN 唇膏寬價差 exact-identity matcher 更新後的 `scheduler.py``services/marketplace_product_matcher.py` 行數;此處只更新 inventory不變更模組化決策。
- 2026-05-21 追記:同步過期 EDM / seasonal promo crawler 排程改為 opt-in、NIVEA/OPI 搜尋 noise 與 identity anchor 補強後的 `run_scheduler.py``services/marketplace_product_matcher.py` 行數;此處只更新 inventory不變更模組化決策。
- 2026-05-21 追記:同步 Recipe Box 多效提亮防曬霜同款漂移比對補強後的 `services/marketplace_product_matcher.py` 行數;此處只更新 inventory不變更模組化決策。
- 2026-05-21 追記:同步 browse.sh 診斷計畫寫入 `competitor_match_attempts` 後的 `services/competitor_price_feeder.py` 行數;此處只更新 inventory不變更模組化決策。
- 2026-05-24 追記:同步背景 PChome 近門檻身份回收與 focused identity 系列更新後的 `services/marketplace_product_matcher.py` 行數;此處只更新 inventory不變更商品比對行為。
- 2026-05-24 追記:同步 111 fallback circuit breaker、NemoTron 決策信封與 Telegram template governance 後的 `run_scheduler.py``services/ollama_service.py``services/nemoton_dispatcher_service.py``services/telegram_templates.py` 行數;此處只更新 inventory不變更模組化決策。
- 2026-05-24 追記:同步 PChome 覆核頁 fast-count、輕量 render 與重算可採用指標後的 `routes/dashboard_routes.py` 行數;此處只更新 inventory不變更 dashboard 行為。
- 2026-05-24 追記:同步 PChome rescore audit 最新狀態口徑與單位價 multiplier 修正後的 `services/marketplace_product_matcher.py` 行數;此處只更新 inventory不變更拆分策略。
- 2026-05-24 追記:同步 PChome review queue 決策信封合併後的 `services/competitor_intel_repository.py` 行數;此處只更新 inventory不變更拆分策略。
- 2026-05-25 追記:同步背景 embedding 讀取 `host_health_probes` skip guard 後的 `services/ollama_service.py` 行數;此處只更新 inventory不變更 Ollama 路由決策。
- 2026-05-29 追記:同步 PChome near-threshold / focused identity 回收系列後的 `services/marketplace_product_matcher.py` 行數;此處只更新 inventory不變更拆分策略。
## 超過 800 行檔案清單
## 達到或超過 800 行檔案清單
| 行數 | 檔案 | 分類 | 拆分方向 |
|---:|---|---|---|
| 5240 | `routes/openclaw_bot_routes.py` | P0 巨型 Blueprint | route / bot command service / report service / scheduler hook |
| 2707 | `scheduler.py` | P0 排程總管 | task registry / crawler jobs / report jobs / notification jobs |
| 2653 | `routes/sales_routes.py` | P0 巨型 Blueprint | page routes / API routes / chart query service / calendar service |
| 1743 | `routes/ai_routes.py` | P1 AI Blueprint | route glue / AI orchestration service / prompt builders |
| 9225 | `routes/openclaw_bot_routes.py` | P0 巨型 Blueprint | route / bot command service / report service / scheduler hook;禁止再新增市場情報入口 |
| 5499 | `services/ppt_generator.py` | P0 報表生成巨型 service | deck orchestration / slide builders / chart builders / report type registry |
| 3186 | `routes/sales_routes.py` | P0 巨型 Blueprint | page routes / API routes / chart query service / calendar service;分析頁新增功能先抽 `services/sales/` |
| 2973 | `scheduler.py` | P0 排程總管 | task registry / crawler jobs / report jobs / notification jobs市場情報只能透過獨立 job module 掛入 |
| 2731 | `services/openclaw_strategist_service.py` | P0 OpenClaw service | prompt builders / report composer / strategy rules |
| 3681 | `routes/admin_observability_routes.py` | P0 觀測台巨型 Blueprint | `services/observability_query_service.py` / `services/observability_action_service.py` / route glue |
| 1796 | `routes/ai_routes.py` | P1 AI Blueprint | route glue / AI orchestration service / prompt builders |
| 2154 | `services/nemoton_dispatcher_service.py` | P1 NemoTron service | NIM client / tool-call parser / action dispatcher |
| 2535 | `routes/dashboard_routes.py` | P1 Dashboard Blueprint | competitor decision overview / dashboard query service首頁資料整併需抽 service |
| 1485 | `routes/vendor_routes.py` | P1 Vendor Blueprint | route glue / stockout mutation/emailV2 page query、stockout list/batches API query、vendor list/detail query 已抽到 `services/vendor_stockout_query_service.py` |
| 1345 | `services/ppt_generator.py` | P1 報表生成 service | deck orchestration / slide builders / chart builders |
| 1339 | `services/nemoton_dispatcher_service.py` | P1 NemoTron service | NIM client / tool-call parser / action dispatcher |
| 1300 | `services/openclaw_strategist_service.py` | P1 OpenClaw service | prompt builders / report composer / strategy rules |
| 1209 | `app.py` | P1 bootstrap | 保持只做 app setup繼續往 app_factory / extension setup 抽 |
| 1079 | `routes/cicd_routes.py` | P2 CI/CD Blueprint | route glue / CI query service / deployment action service |
| 1024 | `routes/dashboard_routes.py` | P2 Dashboard Blueprint | competitor decision overview / dashboard query service目前工作樹已有未提交大段新增邏輯 |
| 986 | `services/telegram_bot_service.py` | P2 Telegram service | command handlers / message formatters / bot client |
| 1390 | `services/telegram_bot_service.py` | P1 Telegram service | command handlers / message formatters / bot client |
| 1237 | `app.py` | P1 bootstrap | 保持只做 app setup繼續往 app_factory / extension setup 抽Phase 42 只做 metadata table name 對齊 |
| 2149 | `services/elephant_alpha_autonomous_engine.py` | P1 ElephantAlpha engine | HITL / executor / planning policy |
| 970 | `routes/cicd_routes.py` | P2 CI/CD Blueprint | route glue / CI query service / deployment action service |
| 1250 | `run_scheduler.py` | P2 scheduler entrypoint | observability jobs / token report jobs / task registration 分離 |
| 916 | `services/ppt_auto_generation_service.py` | P2 PPT 自動產線 service | schedule resolver / generation queue / missing report planner |
| 966 | `services/trend_crawler.py` | P2 crawler service | source adapters / parser / persistence |
| 946 | `services/elephant_alpha_autonomous_engine.py` | P2 ElephantAlpha engine | HITL / executor / planning policy |
| 829 | `routes/export_routes.py` | P2 Export flow | export command/router glue / file path / download orchestration |
| 818 | `services/import_service.py` | P2 import service | validators / import writers / report builders |
| 942 | `services/learning_pipeline.py` | P2 RAG learning pipeline | distiller / promotion gate / persistence / telemetry |
| 940 | `services/import_service.py` | P2 import service | validators / import writers / report builders |
| 1071 | `services/telegram_templates.py` | P2 Telegram templates | alert template groups / channel-specific formatting / reusable render helpers |
| 867 | `services/token_report_service.py` | P2 token report service | query / aggregation / chart payload / notification formatting |
| 4865 | `services/marketplace_product_matcher.py` | P2 marketplace matcher | identity parsing / unit-comparable scoring / search term quality / persistence normalization |
| 865 | `routes/daily_sales_routes.py` | P2 Daily Sales Blueprint | route glue / export helpers / daily query and formatting service |
| 1266 | `services/ollama_service.py` | P2 Ollama client | host health / request client / fallback policy / response parsing |
| 849 | `services/pchome_crawler.py` | P2 PChome crawler | search fetch / parsing / fallback source handling / rate limit policy |
| 1100 | `services/code_review_pipeline_service.py` | P2 Code review pipeline service | scan orchestration / finding normalization / persistence adapter |
| 953 | `routes/export_routes.py` | P2 Export flow | export command/router glue / file path / download orchestration |
| 816 | `services/ppt_vision_service.py` | P2 PPT vision QA service | runtime state / queue status / model probe / audit execution 分離 |
| 2149 | `services/competitor_price_feeder.py` | P2 competitor price feeder | crawler scheduling / price normalization / retryable candidate recovery / cache strategy |
| 1535 | `services/competitor_intel_repository.py` | P2 competitor intel repository | review queue query / cache shaping / formatting helpers |
| 805 | `routes/bot_api_routes.py` | P2 Bot API Blueprint | route glue / bot action service |
| 805 | `services/competitor_price_feeder.py` | P2 competitor price feeder | crawler scheduling / price normalization / cache strategy |
| 1319 | `routes/market_intel_review_report_routes.py` | P2 market intel review report Blueprint | review report route glue / export payload / phase handoff orchestration |
| 917 | `routes/market_intel_routes.py` | P2 market intel Blueprint | page route / API route glue / MCP gate route registration helper |
| 1965 | `services/market_intel/deployment_readiness.py` | P2 market intel deployment readiness | preflight gates / readiness payload / route contract helpers |
| 846 | `services/market_intel/candidate_queue_review_ai_summary_persistence_telegram_dispatch_report_catalog_record_run_receipt.py` | P2 market intel review receipt pipeline | AI summary / persistence / Telegram dispatch / report catalog run receipt orchestration |
## 市場情報開發前置禁區
- 不得把跨平台活動頁、商品池、比對審核 API 新增到 `routes/sales_routes.py``routes/dashboard_routes.py``app.py`
- 不得把 MOMO / PChome / Coupang / Shopee adapter 寫進 `scheduler.py` 或既有 crawler 巨檔;必須放在 `services/market_intel/adapters/`
- 不得把市場情報商品塞回 `promo_products` 作為唯一真相;新資料以 `market_*` schema 為主,舊表只可做相容讀取或明確雙寫過渡。
- 不得在第一階段啟用正式排程或大量入庫;必須先 feature flag 關閉、dry-run、run log、rate limit 與 rollback path。
- 新市場情報 UI 必須先使用共用 V2 token / 分析頁元件規範,避免複製 `templates/sales_analysis.html` 的巨型 template 模式。
## 工作項目
1. P0持續拆 `routes/openclaw_bot_routes.py`Telegram API helper 已搬到 `services/openclaw_bot/telegram_api.py`Inline Keyboard builders 已搬到 `services/openclaw_bot/menu_keyboards.py`,下一步拆 report formatting 或 command dispatcher。
2. P0`routes/sales_routes.py`,先把 chart/query/calendar 計算搬到 `services/sales/`
3. P0`scheduler.py`,建立 `jobs/``services/scheduler/` task registry。
4. P1 `routes/ai_routes.py``routes/vendor_routes.py` 的資料處理移出 routeVendor V2 page query、stockout API list/batches、vendor list/detail 已完成,下一步可抽 email grouping 或 vendor mutation service。
5. P1PPT / NemoTron / OpenClaw 大 service 拆成 client、parser、composer、policy
6. P2對 800-1100 行檔案採「碰到就順手抽」策略,但不可讓淨行數繼續增加
4. P0 `routes/admin_observability_routes.py`,先搬純查詢函式到 `services/observability_query_service.py`,再搬 AutoHeal / Code Review / AiderHeal / throttle mutation 到 `services/observability_action_service.py`
5. P1`routes/ai_routes.py``routes/vendor_routes.py` 的資料處理移出 routeVendor V2 page query、stockout API list/batches、vendor list/detail 已完成,下一步可抽 email grouping 或 vendor mutation service
6. P1把 PPT / NemoTron / OpenClaw / Telegram 大 service 拆成 client、parser、composer、policy
7. P2對 800-1100 行檔案採「碰到就順手抽」策略,但不可讓淨行數繼續增加。
8. 市場情報:先建獨立 `services/market_intel/``routes/market_intel_routes.py``database/market_intel_models.py`,再評估是否接進 scheduler registry。
## 守門

View File

@@ -0,0 +1,338 @@
# Current Execution Queue 2026-05-24
> 目的:把目前使用者要求的核心產品優化整理成單一執行佇列,避免 UI、比價、PPT、AI 觀測台與部署驗證漏項。
> 原則:準確率優先;不放寬 MOMO / PChome 全域比對門檻;正式部署不碰 `momo-db`;每個工作流都需有測試或正式 smoke。
## 0. 部署與驗證通道基準
- 確認 `main`、Gitea、正式環境版本一致。
- 修復或確認 SSH / Gitea / 188 hop 可用。
- 每次上線只 recreate `momo-app``scheduler``telegram-bot`,禁止使用 `--remove-orphans`,禁止影響 `momo-db`
- 2026-05-24 21:33 CST 狀態:`main` 已推 Gitea 並部署到 188正式 `/health``V10.451`。本輪只 recreate `momo-app``scheduler``telegram-bot` 未重建但保持 healthy未使用 `--remove-orphans`,未碰 `momo-db`。Smoke 通過:主要頁面 HTTP 200、三個 app 容器 healthy、`/api/pchome-review/queue` 可用於 `recoverable_low_score` / `legacy_low_score` read-only 查詢,且 10 分鐘錯誤 log 未見 Traceback / ERROR。
- 2026-05-24 22:17 CST 狀態:`main` 已推 Gitea 並部署到 188正式 `/health``V10.453`。本輪 recreate `momo-app``scheduler``telegram-bot`;未使用 `--remove-orphans`,未碰 `momo-db`。Smoke 通過:三個 app 容器 healthy、Gemini hard disabled 且 24 小時 `ai_calls` 無 Gemini provider、Ollama 順序維持 GCP-A → GCP-B → 111、`/api/pchome-review/queue` 三個 status 查詢成功、rescore audit read-only `selection_mode=latest_sku_only`
- 2026-05-24 22:55 CST 狀態:`main` 已推 Gitea 並部署到 188正式 `/health``V10.455`。本輪 recreate `momo-app``scheduler``telegram-bot`;未使用 `--remove-orphans`,未碰 `momo-db`。Smoke 通過:三個 app 容器 healthy、EventRouter `decision_envelope` 直送不進 L1/L2 AI handler、Telegram 信封顯示標的 SKU 與 PChome 候選、Gemini hard disabled 且 24 小時 `ai_calls` 無 Gemini provider、Ollama 順序維持 GCP-A → GCP-B → 111、`/api/pchome-review/queue?review_status=rescore_accepted` 查詢成功、10 分鐘錯誤 log 未見 Traceback / ERROR / CRITICAL。已執行 `--retract-variant-accepted`,最新 `rescore_accepted_current``variant_selection_review` 殘留為 0。
- 2026-05-24 23:05 CST 狀態:`main` 已推 Gitea 並部署到 188正式 `/health``V10.456`。本輪 recreate `momo-app``scheduler``telegram-bot`;未使用 `--remove-orphans`,未碰 `momo-db`。Smoke 通過:三個 app 容器 healthy、`/api/pchome-review/queue?review_status=rescore_accepted` 每筆帶 `decision_envelope`、guardrail `can_auto_execute=false`、Gemini hard disabled 且 24 小時 `ai_calls` 無 Gemini provider、Ollama 順序維持 GCP-A → GCP-B → 111、5 分鐘三容器錯誤 log 未見 Traceback / ERROR / CRITICAL。
- 2026-05-24 23:17 CST 狀態:`main` 已推 Gitea 並部署到 188正式 `/health``V10.457`。本輪 recreate `momo-app``scheduler``telegram-bot`;未使用 `--remove-orphans`,未碰 `momo-db`。Smoke 通過:三個 app 容器 healthy、Dashboard PChome 覆核頁顯示 `dashboard-review-envelope` 與 HITL、`/api/pchome-review/queue?review_status=rescore_accepted` 仍帶 `decision_envelope``can_auto_execute=false`、Excel flatten helper 輸出決策信封 ID/資料品質/自動執行允許/證據摘要、Gemini hard disabled 且 24 小時 `ai_calls` 無 Gemini provider、Ollama 順序維持 GCP-A → GCP-B → 111、5 分鐘三容器錯誤 log 未見 Traceback / ERROR / CRITICAL。
- 2026-05-24 23:30 CST 狀態:`main` 已推 Gitea 並部署到 188正式 `/health``V10.458`。本輪 recreate `momo-app``scheduler``telegram-bot`;未使用 `--remove-orphans`,未碰 `momo-db`。Smoke 通過:三個 app 容器 healthy、`summarize_review_decision_envelopes()` 產生 3 條 HITL 摘要且全數 `can_auto_execute=false``_fetch_competitor_summary()``review_decision_text``/api/pchome-review/queue?review_status=rescore_accepted` 仍帶 `decision_envelope``can_auto_execute=false`、核心頁面 `/daily_sales``/growth_analysis``/observability/ppt_audit_history``/market_intel/matches``/vendor-stockout/list` HTTP 2005 分鐘三容器錯誤 log 未見 Traceback / ERROR / CRITICAL最新 `rescore_accepted_current``variant_selection_review` 殘留為 0。
- 2026-05-24 23:43 CST 狀態:`main` 已推 Gitea 並部署到 188正式 `/health``V10.459`。本輪 recreate `momo-app``scheduler``telegram-bot`;未使用 `--remove-orphans`,未碰 `momo-db`。Smoke 通過:三個 app 容器 healthy、`/api/pchome-review/queue?review_status=protected_existing_match` 輸出 `existing_match_conflict`,建議動作為 `compare_existing_identity``can_auto_execute=false`、Dashboard protected filter / daily / growth / PPT audit HTTP 2005 分鐘三容器錯誤 log 未見 Traceback / ERROR / CRITICAL。
- 2026-05-24 23:59 CST 狀態:`main` 已推 Gitea 並部署到 188正式 `/health``V10.460`。本輪 recreate `momo-app``scheduler``telegram-bot`;未使用 `--remove-orphans`,未碰 `momo-db`。Smoke 通過:三個 app 容器 healthy、`scripts/check_sales_charts_runtime.js --base-url https://mo.wooo.work --routes /daily_sales,/growth_analysis` 通過daily/growth 主要 canvas 均有 Chart.js instance、非零資料點與彩色像素核心頁面 `/daily_sales``/growth_analysis``/observability/ppt_audit_history`、PChome protected queue API HTTP 2005 分鐘三容器錯誤 log 未見 Traceback / ERROR / CRITICAL。
- 2026-05-25 08:12 CST 狀態:`main` 已推 Gitea 並部署到 188正式 `/health``V10.461`。本輪 recreate `momo-app``scheduler``telegram-bot`;未使用 `--remove-orphans`,未碰 `momo-db`。Smoke 通過:三個 app 容器 healthy、Dashboard template 已顯示「尚未搜尋」與「尚未進入 PChome 補抓」、Gemini hard disabled 且 24 小時 `ai_calls` 無 Gemini provider、Ollama 順序維持 GCP-A → GCP-B → 1115 分鐘三容器錯誤 log 未見 Traceback / ERROR / IntegrityError。
- 2026-05-25 08:18 CST 狀態:`main` 已推 Gitea 並部署到 188正式 `/health``V10.462`。本輪 recreate `momo-app``scheduler``telegram-bot`;未使用 `--remove-orphans`,未碰 `momo-db`。Smoke 通過:三個 app 容器 healthy、Dashboard / AI 中樞 / API / 前端 confirm 均改用「PChome 補抓產線 / 補抓未搜尋 / 未搜尋補抓」、Gemini hard disabled 且 24 小時 `ai_calls` 無 Gemini provider、Ollama 順序維持 GCP-A → GCP-B → 1115 分鐘三容器錯誤 log 未見 Traceback / ERROR / IntegrityError。
- 2026-05-25 08:38 CST 狀態:`main` 已推 Gitea 並部署到 188正式 `/health``V10.464`。本輪 recreate `momo-app``scheduler``telegram-bot`;未使用 `--remove-orphans`,未碰 `momo-db`。Smoke 通過:三個 app 容器 healthy、`/``/?filter=pchome_review``/daily_sales``/growth_analysis``/observability/ppt_audit_history`、PChome rescore queue API HTTP 200。DR.WU 三筆 SKU read-only rescore 全數 `gate_pass=3/3``--apply-accepted` 後 latest 狀態為 `rescore_accepted_current``best_match_score=1.0``price_basis=total_price`;整體 latest counts 變為 `true_low_confidence=778``rescore_accepted_current=34`。5 分鐘 log 未見 Traceback但有既有 `[Embed] all hosts failed` 錯誤,需列入下一輪 Ollama embedding 健康檢查。
- 2026-05-25 10:04 CST 狀態:`main` 已推 Gitea 並部署到 188正式 `/health``V10.465`。本輪 recreate `momo-app``scheduler``telegram-bot`;未使用 `--remove-orphans`,未碰 `momo-db`。Smoke 通過:三個 app 容器 healthy、`/``/daily_sales``/growth_analysis``/observability/ppt_audit_history`、PChome rescore queue API HTTP 200容器內 routing smoke 證明 resolver 回 111 且 `allow_111_fallback=false` 時會改試 GCP-A/GCP-B輸出 `tried=['http://34.87.90.216:11434','http://34.21.145.224:11434']`;真實短 embedding 在 GCP-A `/api/version` timeout、GCP-B 200 情境下成功回 1024 維向量,耗時 4.59 秒。3 分鐘三容器錯誤 log 未見 Traceback / ERROR / CRITICAL。
- 2026-05-25 12:10 CST 狀態:已部署 `V10.467` 到 188正式 `/health``V10.467`。本輪 recreate `momo-app``scheduler``telegram-bot`;未使用 `--remove-orphans`,未碰 `momo-db`。Smoke 通過:三個 app 容器 healthy、`/``/daily_sales``/growth_analysis``/observability/ppt_audit_history`、PChome rescore queue API HTTP 200。Production pilot 將 9 筆 focused exact total-price SKU 追加為 `rescore_accepted_current`,整體 latest counts 從 `true_low_confidence=802` / `rescore_accepted_current=38` 變為 `true_low_confidence=793` / `rescore_accepted_current=47`;目標 SKU 的 `competitor_prices` 最新 `crawled_at` 仍停在 2026-05-222026-05-23確認本輪未寫正式價差表。已知後續GCP-A / GCP-B Ollama `/api/version` 目前連線失敗,背景 embedding 正確沒有落 111但 app/scheduler log 仍會出現 `[Embed] all 2 hosts failed`,需另開 Ollama 健康處理。
- 2026-05-25 12:27 CST 狀態:已部署 `V10.468` 到 188正式 `/health``V10.468`。本輪 recreate `momo-app``scheduler``telegram-bot`;未使用 `--remove-orphans`,未碰 `momo-db`。Smoke 通過:三個 app 容器 healthy、`/``/daily_sales``/growth_analysis``/observability/ppt_audit_history`、PChome review queue API `/api/pchome-review/queue` HTTP 200容器內 mock smoke 證明背景 embedding 在 GCP-A / GCP-B 全失敗後會開啟 60 秒 failure circuit第二筆不再重複打兩台 GCP且不落 111。GCP 維運盤點GCP-A `22/11434` refusedGCP-B `22` open 但現有 key publickey denied部署 smoke 時 GCP-B `11434` 已恢復 200、`get_ollama_host()` 選到 GCP-B111 `/api/version` 可用,但 111 仍不得承接背景 `bge-m3`
- 2026-05-25 12:39 CST 狀態:已部署 `V10.469` 到 188正式 `/health``V10.469`。本輪 recreate `momo-app``scheduler``telegram-bot`;未使用 `--remove-orphans`,未碰 `momo-db`。Smoke 通過:三個 app 容器 healthy、首頁 / daily / growth / PChome review queue HTTP 200、Gemini hard disabled`allow_111_fallback=False` 時 GCP-only embedding 全失敗會開啟 failure circuit 並記 WARNING不再把預期內的背景熔斷打進 ERROR 通道。觀測到 GCP-B `/api/version` 200`/api/embed` 仍可能 15s timeout下一步需修 GCP-A primary 與 GCP-B runner/model 負載。
- 2026-05-25 12:53 CST 狀態:已部署 `V10.470` 到 188正式 `/health``V10.470`。本輪 recreate `momo-app``scheduler``telegram-bot`;未使用 `--remove-orphans`,未碰 `momo-db`。Smoke 通過:三容器 healthy、host health page HTTP 200 並顯示 Runtime 狀態、scheduler probe 寫入 DB。最新 `host_health_probes`GCP-A unhealthy11434 refused、GCP-B unhealthy`EmbedProbe ReadTimeout`, `/api/tags` 仍可列出 4 模型、111 healthy這補上「HTTP API 活著但模型 runtime 卡住」的假健康監控缺口。
- 2026-05-25 13:38 CST 狀態:已部署 `V10.471` 到 188正式 `/health``V10.471`。本輪 recreate `momo-app``scheduler``telegram-bot`;未使用 `--remove-orphans`,未碰 `momo-db`。Smoke 通過:三容器 healthy、首頁 / daily / growth / host_health / ppt_audit_history / PChome review queue HTTP 200。GCP-B `bge-m3` `/api/embed` 直接實測約 6.4s、7.3s、23.5s,原 `OLLAMA_EMBED_MAX_TIMEOUT=15` 與 host health `OLLAMA_HOST_HEALTH_EMBED_TIMEOUT=8` 會誤殺慢但成功的 embedding預設改為 30s。正式容器內 embedding smoke 回 1024 維、耗時 10.07s;手動 host health probe 後最新狀態為 GCP-A unhealthy、GCP-B healthy、111 healthy。背景 embedding 路由安全不變GCP-A → GCP-B不落 111。
- 2026-05-25 14:10 CST 起,`V10.472` 補 rootless GCP Ollama failover 診斷腳本與 DevOps SOP`scripts/ops/diagnose_ollama_gcp_failover.sh` 會檢查 direct GCP-A/GCP-B/111、110 proxy `11435/11436` 與 GCP-B `bge-m3` runtime。現況輸出GCP-A direct `/api/version` failed/refused、GCP-B direct OK、111 OK、110:11435 502、110:11436 OK、GCP-B embed OK110 無免密 sudo`ssh gcp-a` 22 refused、`ssh gcp-b` publickey denied因此 primary 修復需 GCP/SSH 或 110 root 權限。
- 2026-05-25 14:12 CST 起,`V10.473` 進行背景 embedding host_health skip`allow_111_fallback=false` 的背景 embedding 會讀最近 `host_health_probes`,若 GCP-A/GCP-B runtime 已被標 unhealthy直接跳過該節點並開 GCP circuit不等待 30 秒 timeout、不落 111DB 讀取失敗 fail-open。
- 2026-05-25 14:45 CST 起,`V10.474` 補 PChome near-threshold matcher / feeder 下一階段HOOOME 白色經典香氛暖燈、Gdesign Aroma Lava 2.0 進 total-price exactRecipe Box 可撕式水性兒童指甲油保留 identity_review不自動寫正式價差Pavaruni 蠟燭 vs 精油與 DASHING DIVA 不同款式仍不放行。known-id refresh 會對 hard-veto 舊候選跑 fresh search recoverymissing known-id 若 fresh search 只有低分候選,也保留 best candidate + diagnostics不再只記 `refresh_no_result`;正式覆寫保護新增 stronger existing guard。
- 2026-05-25 15:20 CST 起,`V10.475` 補 rescore CLI 與高分錯配防線audit CLI 預設不再只掃 `strong_exact_spec_match`,避免新版 `focused_exact_*` 理由漏掃matcher 對香氛暖燈 S/M/L 尺寸差、NITORI 香氛噴霧器型號差直接 hard veto彩妝色號單邊出現時送 `variant_selection_review`,避免高分但不同 variant 的候選被誤推入 accepted queue。
- 2026-05-25 16:15 CST 起,`V10.476` 補商業條件差防線:即期品、效期/保存期限、盒損、福利品等條件只出現在單側時matcher 加 `commercial_condition_gap` 並送 `variant_selection_review`,不讓同名但商品狀態不同的候選自動進 accepted queue。
- 2026-05-25 19:20 CST 起,`V10.477` 補高分錯配防線SPF 數值不同直接 vetoMAKE UP FOR EVER 定妝噴霧 vs 活氧水不同線直接 veto多款任選對單一款與單側色號改送 `variant_selection_review`,涵蓋私密潔浴露、身體去角質、美體乳液與染眉膏等。
- 2026-05-25 21:05 CST 起,`V10.480` 補 accepted-current 風險樣本防線rom&nd 零絲絨/果凍唇釉 vs 果汁唇釉多款 listing 直接 `romand_lip_line_conflict` hard vetoRelove 潔淨凝露若傳明酸/淨白活性只出現在單側,保留高分但進 `variant_selection_review`1990 融燭燈不同設計(歐式可彎 vs 韓風原木底座)直接 `selection1990_wax_lamp_design_conflict` hard veto。
- 2026-05-25 21:25 CST 起,`V10.481` 補 rescore accepted retraction 工具缺口:退回工具會用當前 matcher 重判 latest `rescore_accepted_current`,凡新版已變 `variant_selection_review / low_score_current` 的舊 accepted 會追加退回 `true_low_confidence`避免人工覆核隊列保留舊版安全閘門放行的候選。Production 已部署 `/health=V10.481`;保守 materialize 15 筆安全 SKU 後再退回 7 筆舊 accepted 變體風險,最新 accepted audit 為 `scanned=89 / gate_pass=89 / still_low=0`
- 2026-05-25 21:47 CST 起,`V10.482` 補 exact variant-safe 回收LUSH 櫻之花身體噴霧 200ml、ARTMIS 金縷梅/蔓越莓私密清潔慕斯 250ml、SO NATURAL FIXX 120ml plain 與 Baan 原味/草莓同 catalog若雙方同品名、同規格且同明確 variant移除過度保守的 `variant_selection_review` 並進 `exact / total_price / price_alert_exact`SO NATURAL 經典款/光澤款/霧面款/夏日款 catalog 對單款 120ml 仍維持人工覆核。Production 已部署 `/health=V10.482`,只 materialize 5 筆新增 exact-line SKU 到 `rescore_accepted_current`latest accepted audit 為 `scanned=94 / gate_pass=94 / still_low=0`,三應用容器 healthy、`momo-db` 未 recreate。
- 2026-05-25 23:03 CST 起,`V10.483` 收斂舊 gate pass 風險NARS 遮瑕蜜任選、LOREAL 玻尿酸啵啵精華水/液態紫熨斗 vs 水光精華、SEBAMED 洗髮乳任選、Schick 舒綺 2-in-1 型號落差、TAICEND 保護膜 vs 噴霧,現在都會保留高分但加 `variant_selection_review` 與專屬 reason不再被 rescore 自動送進 accepted queue。Production 已部署 `/health=V10.483`;目標 5 SKU audit `gate_pass=0 / still_low=5`,並用 `--retract-variant-accepted` 退回 4 筆舊 accepted 變體風險latest accepted audit 為 `scanned=90 / gate_pass=90 / still_low=0`
- 2026-05-25 12:05 CST 狀態:`main` 已部署到 188正式 `/health``V10.467`,待推 Gitea。兩段變更已合併驗證V10.466 rescore duplicate 改看 latest-state7 筆 SKU 最新 attempt 全為 `rescore_accepted_current``competitor_prices` / `competitor_price_history` 目標計數未變V10.467 focused exact matcher 在容器內回 `exact / total_price / price_alert_exact`。本輪 recreate `momo-app``scheduler``telegram-bot`;未使用 `--remove-orphans`,未碰 `momo-db`。Smoke 通過:三容器 healthy、PChome rescore queue API HTTP 200、Gemini 24 小時無 provider 紀錄、Ollama env 順序維持 GCP-A → GCP-B → 111、3 分鐘三容器 log 未見 Traceback / ERROR / CRITICAL / IntegrityError。
## 1. MOMO / PChome 核心比價準確率
- 查正式 `competitor_match_attempts` 最新狀態分布與高量低信心 cohort。
- 以小批次 pilot 處理 `recoverable_low_score`,優先品線:
- DASHING DIVA
- aroma / diffuser / essential oil
- lip / cosmetic variant
- private-care / body-care
- 2026-05-24 22:10 CST 起PChome rescore audit 預設對齊 review queue 最新狀態:先取每個 SKU 最新 attempt再套用 status / reason 篩選;歷史候選回看需明確使用 `--include-historical-candidates`
- 2026-05-24 22:20 CST 起matcher replay 先套用 V10.453 安全修正:`EX8` 型號不視為 `x8` 入數,香氛固體凝膠一側泛稱、一側具體香味/No. 款式走 vetoHerbacin 小甘菊護手霜 20ml brandless 可作窄範圍安全回收。
- 2026-05-24 22:42 CST 起feeder / rescore audit 套用 V10.454 安全閘門:`identity_review` / `manual_review` / `variant_selection_review` 的近門檻候選只能留在覆核,不能由 replay、refresh 或 `accepted_current` 入隊語意自動寫正式 PChome 價差。
- 2026-05-24 22:48 CST 已執行 production rescore 入隊745 筆 `true_low_confidence` 中先有 2 筆通過舊 gateV10.454 gate 補上 `variant_selection_review` 排除後SKU `8884618` KATE 多款任選唇膏已退回最新 `true_low_confidence`,最終只保留 SKU `10922465` Herbacin 小甘菊護手霜 20ml 為 `rescore_accepted_current` 人工覆核 attempt正式價格表未寫入Dashboard / competitor intel cache 已清除。
- 2026-05-24 22:44 CST 起rescore audit 補 `--retract-variant-accepted` 工具化退回路徑;若最新 `rescore_accepted_current` 仍帶 `variant_selection_review`,只追加 `true_low_confidence` attempt不刪歷史、不寫正式價格表。
- 只新增窄範圍、可解釋 matcher 規則。
- 保留 `MIN_MATCH_SCORE``identity_veto`、既有正式候選覆寫保護。
- 驗收:`matched` 有增加、目標 `low_score` 下降、`needs_review` 不異常上升、無明顯跨色號/跨款式/跨劑型錯配。
## 2. 商品列表與人工覆核閉環
- 商品列表不得再大量顯示籠統「待對比」。
- 將狀態拆成:尚未搜尋、價格過期待刷新、近門檻可救回、證據不足、既有強配對保護、已排除、需單位價比較、找不到同款。
- 每筆覆核要顯示候選 PChome 商品、候選價、match score、診斷原因、下一步動作。
- 人工採用 / 否決 / 單位價 / 補搜尋必須能回寫 review queue並影響 feeder 後續行為。
- 2026-05-25 00:15 CST 起PChome 補抓操作入口同步收斂為「PChome 補抓產線 / 補抓未搜尋 / 未搜尋補抓」,包含 Dashboard、AI 中樞、前端 confirm 與 API 回覆,不再讓操作入口殘留籠統「待比對」。
- 2026-05-25 00:06 CST 起,尚未進入 PChome 搜尋/補抓的商品列表文案改為「尚未搜尋」與「尚未進入 PChome 補抓」,不再顯示籠統「待比對」,避免和低信心待人工覆核混淆。
- 2026-05-24 23:40 CST 起,`protected_existing_match` 的 review `decision_envelope` 會解析 `existing_match_conflict`,列出既有正式候選、新候選、雙方 score 與 delta這類案件仍不可自動覆蓋正式價差但人工覆核、Agent 與 PPT 不再只看到籠統「既有保護」。
## 2.1 近門檻 / 高信心待審 matcher 補強
- 2026-05-25 08:30 CST 起rescore audit 支援 `--sku` repeatable 精準篩選production pilot 可只指定 3-10 個 SKU 執行 read-only audit 或 `--apply-accepted`,避免寬範圍掃描誤把不同 cohort 混在同一次驗證。
- 2026-05-25 08:25 CST 起,`DR.WU / DR WU / DRWU / 達爾膚` 視為同一品牌 alias正式樣本中的 DR.WU 玻尿酸保濕精華乳 50ML、2入組與杏仁酸亮白煥膚精華 18% 30ML 2入組在不調整全域門檻下可由 brandless identity review 回到 exact total-price lane。
- 2026-05-25 08:36 CST production pilotSKU `10362820``10653216``10653329` 已從 `true_low_confidence` materialize 為 `rescore_accepted_current`,只進人工覆核隊列,不寫 `competitor_prices`
- 2026-05-25 11:55 CST 起rescore audit duplicate 判斷只看最新 attempt若歷史已有 accepted 但後續 crawler 又追加低信心列,可重新 materialize 成最新 `rescore_accepted_current`。Production pilot 已將 SKU `14756069``11159042``13842560``8394210``15192547``10509765``10603780` 入人工覆核隊列;正式 `competitor_prices` / `competitor_price_history` 未寫入或改變。
- 2026-05-25 12:20 CST 起matcher 新增 `focused_exact_total_price_safe` 窄範圍通道;目前只覆蓋 3W CLINIC 粉底液 2入、花美水凝膠 3支、The Ordinary 咖啡因 EGCG 30ml、KUSSEN 屁屁膏 3入、Bone 擴香禮盒、1990 融燭燈白色款與 CANMAKE 淚袋盤等已確認同款樣本。這讓高信心 `exact/manual_review` 能轉為 `exact/total_price` 供 rescore pilot 入人工覆核DASHING DIVA、唇彩、香味、色號/款式敏感商品仍不放行。
- 2026-05-25 12:25 CST production pilotSKU `6101639``10074951``7760902``TP00074980000005``14774766``10142589``10262470``10262471``11308520` 已從 `true_low_confidence` materialize 為 `rescore_accepted_current`,全數 `exact/total_price/price_alert_exact` 且理由含 `focused_exact_total_price_safe`。SKU `6101784` 因「即期品」商業條件不同,刻意保留在 `true_low_confidence`,不納入本輪自動入隊。
- 2026-05-25 14:45 CST 起matcher 擴充至香氛/精油近門檻安全 cohortHOOOME 白色經典香氛暖燈與 Gdesign Aroma Lava 2.0 可進 `exact/total_price/price_alert_exact`Recipe Box 可撕式水性兒童指甲油只進 `identity_review`,因兒童指甲油仍可能藏色款/款式。DASHING DIVA 與 Pavaruni cross-type 負例已補測試,避免跨款式、跨劑型誤配。
- 2026-05-25 15:20 CST 起新增三個正式觀察到的高分負例防線PRAY 守夜人暖燈 L vs S、NITORI 香氛噴霧器 5510 vs YX168、LA MER 氣墊粉霜通用 listing vs `11 Rosy Ivory` 色號。前兩者 hard veto後者保留高分但不進 accepted queue。
- 2026-05-25 16:15 CST 起新增商業條件差負例KAMERIA 足膜、3W CLINIC 粉底液、Sisley 全能乳液等若一側標示即期/效期/盒損,仍可顯示高相似度,但只進 identity review不自動入 accepted queue。
- 2026-05-25 19:20 CST 起新增高分負例Jealousness SPF25 vs SPF50、MAKE UP FOR EVER 超光肌控油定妝噴霧 vs 超光肌活氧水、rom&nd 染眉膏通用 listing vs `03 摩登米`、Lactacyd 多款潔浴露 vs 單一亮肌柔滑、我的心機多款身體去角質 vs 單一香型。前兩者 hard veto其餘進 identity review。
- 2026-05-25 20:05 CST 起,新增高分錯配 / catalog 變體防線AUS LIFE 檸檬草 vs 茶樹滾珠精油、NOW 椰子油膏 vs 乳木果油、港香蘭漢本 vs 艾魔菈爽身粉改為 hard veto多色 / 多香 / 數字區間 catalog 對單一款式KATE 粉餅盒、植村秀眉筆、PERIPERA 01~07 眼線膠筆、Jo Malone 車用擴香蕊芯等)只進 `variant_selection_review`
- 2026-05-25 20:35 CST 起,依 production audit 續補二階風險:同規格但一側為潔膚露、一側為修護乳/乳液直接 `cleanser_lotion_line_conflict` hard veto私密防護慕絲多款可選 vs 單一香型、滋養霜單側清爽型只進 `variant_selection_review`
- 2026-05-25 21:05 CST 起,依 accepted-current 二次抽樣續補三類風險rom&nd 唇釉不同品線不可互收Relove 潔淨凝露傳明酸/淨白變體不可自動 accepted1990 融燭燈同色但不同燈座/結構不可互收。下一步先部署 V10.480,再回查 accepted-current 是否仍有上述 4 筆風險 SKU。
- 2026-05-25 21:25 CST 起accepted queue 清潔不再只靠舊 `diagnostic_codes``--retract-variant-accepted` 改為先抓 latest accepted再用當前 matcher 判斷是否需要退回。這能清掉 V10.480 後才被新規則判為 `variant_selection_review` 的舊 accepted。正式最新狀態`true_low_confidence=751``rescore_accepted_current=89``identity_veto=3994``matched=1570``unit_comparable=379`
- 2026-05-25 23:45 CST 起,`V10.484` 拆分 manual gate exact 與型錄風險POWERMAN 男性私密養護液 30ml、PHYSIOGEL AI 冰鎮精華露 200ml 2入、TS6 緊彈水嫩凝膠 40g、DERMA 寶寶洗髮沐浴露 150/500ml、Clarins 黃金亮眼萃 20ml、Cetaphil 長效潤膚乳 237/473ml 等明確同款可走 `exact / total_price / price_alert_exact`COCODOR 大豆蠟燭單側多款任選保留 `variant_selection_review`Pavaruni 雙側 20 香味蠟燭保持 total-price exact。測試`tests/test_marketplace_product_matcher.py``tests/test_competitor_match_attempts_persistence.py``tests/test_competitor_match_attempt_rescore_audit.py` 通過。
- 2026-05-25 23:55 CST 起,`V10.485` 補 NITORI 香氛噴霧器短型號防線near-threshold read-only pilot 中唯一 gate pass 為 5510 vs J82 LBR已判定不該入隊matcher 將 `J82` 這類短英數型號納入 NITORI diffuser model conflict與 5510 / YX168 等不同型號一樣 hard veto。Production 已部署 `/health=V10.485`120 筆 near-threshold audit 由 `gate_pass=1``gate_pass=0`accepted audit `scanned=89 / gate_pass=89 / still_low=0`
- 2026-05-29 起,`V10.486` 補 PChome near-threshold 風險邊界NEW DIRECTIONS 甜杏仁油 vs 酪梨油直接 hard vetoCOCODOR 經典擴香瓶多款任選、KAMERIA 足膜任選三款、Hakugen 白元入浴劑橘盒/綠盒不同變體都保留 `variant_selection_review`,不進可採用 gate。Production 已部署 `/health=V10.486`240 筆 near-threshold audit `gate_pass 83→79``identity_veto 0→1``still_low 157→160`
- 2026-05-29 起,`V10.488` 新增市場情報 MCP Fetch Run Receipt 安全預覽 gate只審核操作員 dry-run receipt不執行 CLI、不抓外站、不寫 DB。
- 2026-05-29 起,`V10.489` 補 PChome 低分同款人工覆核回收與 gate-pass 風險邊界TS6 超美白香氛誘霜 120g/ml、W 修護保養蝸牛特潤修護面膜 6 片、Derma 大地 Eco 植萃護膚油 2 入,從低信心升成 `identity_review` 候選Clarins 輕盈美體護理油 vs 身體調和護理油、台塑生醫嬰兒沐浴/洗髮組合數量反轉、isLeaf 私密慕絲香型數量不一致改 hard vetoHOOOME 大理石暖燈 vs 泛稱經典款只留 `variant_selection_review`,不進 total-price accepted。Production 已部署 `/health=V10.489`500 筆 read-only audit 由 V10.486 基線 `gate_pass=129 / identity_veto=1 / still_low=370` 收斂為 `gate_pass=124 / identity_veto=4 / still_low=372`,三應用容器 healthy、`momo-db` 未 recreate。
- 2026-05-31 起,`V10.490` 補 ElephantAlpha / OpenClaw 舊策略 action 相容:正式日誌觀察到 `agent=openclaw action=generate_market_strategy` 被當未知步驟丟錯;此類 OpenClaw strategy 產生步驟已定義為 advisory skipped只記 warning不觸發 circuit breaker、不執行外部策略、不影響價格行動。測試覆蓋 `generate_market_strategy``generate_resource_optimization_strategy`,未知 action 仍維持 fail-fast。
- 2026-05-31 起,`V10.491` 新增市場情報 MCP Fetch Result Parser Review gate在 receipt gate 後只審核操作員 shell parser 貼回的結構化摘要,對齊 source/path、公開 URL、候選必要欄位、小批次上限、raw HTML/secret/side-effect 風險;仍不讀 artifact、不執行 CLI、不連外、不寫 DB、不掛 scheduler。
- 2026-05-31 起,`V10.492` 收緊 PChome 近門檻自動回刷:`run_retryable_candidate_revalidation()` 只回刷 `recoverable_low_score` 與 legacy `low_score / refresh_low_score`,且 SQL 端要求 `hard_veto=false``comparison_mode=exact_identity`、diagnostic reasons 命中同品線/identity anchor`identity_veto``unit_comparable``true_low_confidence` 不再進每日自動回刷隊列,需等待新證據或人工處理。
- 2026-05-31 起,`V10.493` 新增市場情報 MCP Fetch Candidate Handoff Review gate在 parser review 通過後只審核候選交接包,要求 source/candidate key 完全對齊、queue policy 維持 manual preview、小批次上限與操作員無寫入/無連外/無排程確認;仍不建立 queue、不寫 DB、不讀 artifact、不連外、不掛 scheduler。
- 2026-05-31 起,`V10.494` 新增市場情報 MCP Fetch Candidate Queue Review gate在 handoff review 通過後只審核人工 queue review 草案,要求候選 key 完全對齊、review_state 只停在 `needs_review`、allowed actions 限人工操作、queue_write_status 維持 `not_persisted`;仍不建立 queue、不更新 review_state、不寫 DB、不連外、不掛 scheduler。
- 2026-05-31 起,`V10.495` 新增市場情報 MCP Fetch Candidate Queue Writer Preflight gate在 queue review 通過後只審核 writer preflight 草案,要求 target table、write mode、dedupe strategy、insert columns、payload rows 與候選 key 完全對齊;仍不開 DB、不執行 CLI、不建立 queue、不更新 review_state、不寫 DB、不連外、不掛 scheduler。
- 2026-05-31 起,`V10.496` 新增市場情報 MCP Fetch Candidate Queue Writer CLI Review gate在 writer preflight 通過後只審核 CLI review 草案,要求 script path、target table、preflight id、row count、candidate/dedupe keys 與 read-only command argv 對齊;仍不執行 CLI、不讀 approval token、不寫檔、不開 DB、不寫 queue、不掛 scheduler。
- 2026-05-31 起,`V10.497` 新增市場情報 MCP Fetch Candidate Queue Writer Run Package Review gate在 CLI review 通過後只審核 operator run package 草案,要求 artifact manifest、operator shell command sequence、package identity、candidate/dedupe keys 與 CLI review 對齊;仍不產檔、不讀 approval token、不執行 CLI、不開 DB、不寫 queue、不掛 scheduler只放行到 run readiness review。
- 2026-05-31 起,`V10.498` 新增市場情報 MCP Fetch Candidate Queue Writer Run Readiness gate在 run package review 通過後只審核 operator readiness 證據,要求 run readiness artifact、reviewed sample、備份、read-only preflight 與 post-write smoke 路徑安全,並確認 CLI-only、approval token shell-only、無 API/DB/file/scheduler 副作用;仍不產檔、不讀 token、不執行 CLI、不開 DB、不寫 queue、不掛 scheduler只放行到後續 run receipt review。
- 2026-05-31 起,`V10.499` 新增市場情報 MCP Fetch Candidate Queue Writer Run Receipt Review gate在 run readiness 通過後只審核操作員 shell writer run 的 receipt 摘要,要求 readiness linkage、run package id、候選/dedupe keys、writer output、post-write smoke、backup path 與 operator confirmation 對齊;仍不讀 receipt 原文、不讀 token、不執行 CLI、不開 DB、不寫 queue、不做 post-write query、不掛 scheduler只放行到 closeout review。
- 2026-05-31 起,`V10.500` 新增市場情報 MCP Fetch Candidate Queue Writer Run Closeout Review gate在 receipt review 通過後只審核 operator closeout 摘要,要求 receipt linkage、closeout artifact、receipt review artifact、post-closeout inventory plan、writer output / post-write smoke / backup manifest、rollback note 與 operator confirmation 對齊;仍不讀 receipt 原文、不讀 token、不執行 CLI、不開 DB、不寫 queue、不做 post-closeout query、不掛 scheduler只放行到 read-only post-closeout inventory review。
- 2026-05-31 起,`V10.501` 新增市場情報 MCP Fetch Candidate Queue Writer Post-Closeout Inventory Review gate在 closeout review 通過後只審核 operator live inventory read-only 摘要,要求 closeout linkage、row count、inventory artifact、closeout review artifact、read-only query result、missing/duplicate rows 與 operator confirmation 對齊;仍不讀 token、不執行 CLI、不開 DB、不寫 queue、不做 inventory query、不掛 scheduler只放行到 candidate queue review handoff。
- 2026-05-31 起,`V10.502` 修正 AiderHeal 自動修復診斷鏈:先檢查 ADR-020 檔案白名單再執行 110 preflight`tests/` finding 會明確略過而不誤報 repo preflightCode Review 完成通知會把全數不在白名單的 finding 標成需人工處理,不再宣稱已觸發 AiderHeal白名單放行 `services/routes/database` 子目錄 Python 檔preflight 通知帶遠端錯誤細節,健康檢查接受 `/health``healthy`
- 2026-05-31 起,`V10.503` 新增市場情報 MCP Fetch Candidate Queue Writer Review Handoff gate在 post-closeout inventory review 通過後只審核 operator candidate queue review handoff 摘要,要求 inventory linkage、handoff identity、target table、row count、artifact paths、review contract、forbidden API actions 與 operator confirmation 對齊;仍不讀 token、不執行 CLI、不開 DB、不寫 queue、不更新 review_state、不掛 scheduler只放行到人工 candidate queue review。
- 2026-05-31 起,`V10.504` 新增市場情報 MCP Fetch Candidate Queue Writer Review Inventory gate在 writer review handoff 通過後只審核 operator read-only candidate queue inventory 摘要,要求 handoff identity、target table、row count、dedupe keys、review_state、artifact paths、read-only query result、missing/duplicate rows 與 operator confirmation 對齊;仍不讀 token、不執行 CLI、不開 DB、不寫 queue、不更新 review_state、不做 inventory query、不掛 scheduler只放行到後續人工 candidate queue review。
- 2026-05-31 起,`V10.505` 新增市場情報 MCP Fetch Candidate Queue Writer Review Decision gate在 review inventory 通過後只審核 operator candidate queue review decision 摘要,要求 decision identity、target table、row count、dedupe keys、`needs_review` 現態、允許決策、evidence refs、matched row exact-identity/variant/overwrite guard 與 operator confirmation 對齊;仍不讀 token、不執行 CLI、不開 DB、不寫 decision record、不更新 review_state、不寫 match result、不補 queue、不掛 scheduler只放行到 decision approval / writer preflight 設計。
- 2026-05-31 起,`V10.506` 新增市場情報 MCP Fetch Candidate Queue Writer Review Decision Approval gate在 review decision 通過後只審核 operator human approval 摘要,要求 decision linkage、approval identity、target table、row count、dedupe keys、`approved_for_writer_preflight` approval result、decision/approval evidence refs、artifact paths、matched row exact-identity/variant/overwrite guard 與 operator confirmation 對齊;仍不讀 token、不執行 CLI、不開 DB、不寫 approval record、不寫 decision record、不更新 review_state、不寫 match result、不補 queue、不掛 scheduler只放行到後續 writer preflight 設計。
- 2026-05-31 起,`V10.509` 新增市場情報 MCP Fetch Candidate Queue Writer Review Decision Approval Writer Preflight gate在 human approval 通過後只審核 operator writer preflight 摘要,要求 approval linkage、writer_preflight_id、target operation、row count、dedupe keys、approved decision 到 target review_state 的逐列映射、decision/approval/preflight evidence refs、matched row exact-identity/variant/overwrite guard 與 operator boundary仍不讀 token、不執行 CLI、不開 DB、不寫 preflight/approval/decision/match、不更新 review_state、不補 queue、不掛 scheduler只放行到後續 CLI review / run package 設計。
- 2026-06-01 起,`V10.566` 新增市場情報 Professional Source Governance gate將 robots/REP、sitemap/lastmod、JSON-LD / schema.org structured data、canonical URL、rate limit、公開資料邊界、provenance、snapshot hash 與 idempotency key 納入 source contract並接上 `/api/market_intel/mcp_professional_source_governance`、UI preview panel、deployment readiness check 與 production smoke target仍不抓外站、不讀 robots/sitemap、不開 DB、不寫檔、不掛 scheduler。
- 2026-06-04 起,`V10.579` 補 PChome 高信心 total-price safe familySAB 私密防護舒緩噴霧 30ml、Herbacin 小甘菊 20ml 護手霜在同款式同規格且無 variant/commercial gap 時可進 `exact / total_price / price_alert_exact`;跨款式反測仍擋在 review`MIN_MATCH_SCORE` 不變。同版將 Code Review GCP-B secondary timeout 收斂到 25 秒GCP-A/GCP-B 都慢時更快回 local degraded。
- 2026-06-04 起,`V10.580` 補 PChome 重複單品組 total-price 窄門與核心油種 veto同品牌、同入數、同基礎規格且名稱高度對齊的重複單品組例如 Bioneo 150ml x2、Cetaphil 150ml x2、Avene 300ml x4、Schick 2+1 入)可進 `exact / total_price / price_alert_exact`;正式部署前估算 213 筆高分 `true_low_confidence` 中僅 7 筆會被自動寫入。NEW DIRECTIONS 甜杏仁油 vs 杏桃核仁油改 hard vetoPaula's Choice 缺 30ml 規格的雙入組仍留 manual review`MIN_MATCH_SCORE` 不變。
- 2026-06-04 起,`V10.581` 將重複單品組安全線接進 retryable revalidation只收 `true_low_confidence` 中舊診斷為 `match_type=exact / price_basis=manual_review`、無 commercial / variant / count / bundle 等阻擋,且命中具名安全商品線的候選;最後仍由最新版 matcher 與 overwrite protection 決定是否寫正式比價。
- 2026-06-04 起,`V10.582` 補 PChome 比價通知專業分級與 Nick 副標身份證據NemoTron 決策信封保留 MOMO / PChome 價格、價差與 7 日業績變化Telegram decision envelope 將 `exact / total_price / price_alert_exact` 等工程路徑翻成直接價格威脅、單位價覆核、身份覆核或壓制告警,並把「單位價/身份未確認不得用總價直接告警」寫進操作邊界。PChome `Nick` 副標會以 `match_name` 參與 matcher比價可用到容量、入數、濃度資訊但不改 UI/DB 正式顯示品名。
- 2026-06-04 起,`V10.583` 補 Paula's Choice 身體乳 PChome Nick 具名 alignment`2%水楊酸身體乳210ml二入` 可和 PChome `Nick` 補出的 `水楊酸身體乳雙入組 / 210ml x2` 對齊並進 safe total-price此版不泛用放寬中文入數`118ml二入組(金蓋限定版)` 對上 PChome 效期品仍維持 manual review。
- 2026-06-04 起,`V10.584` 補 PChome Nick 清洗與 stale recovery 單品窄門Nick 先去 HTML、行銷星號與重複品名避免同一商品副標讓規格被重複計數新增 NIVEA 妮維雅霜 100ml、Schick 舒綺敏感肌除毛刀片 3 入、TS6 沁涼潔淨慕斯 100g 具名 exact total-price alignment。IBL 沐浴/洗髮用途落差、唇色目錄款、效期/限定版差異仍留 review。
- 2026-06-05 起,`V10.601` 收斂 Gemini / 111 治理:正式 `ai_calls` 近 24 小時與近 7 天沒有 Gemini provider舊 K8s/n8n/scripts/docs/Google Drive token 檔中的已知實密鑰改占位符並補全 repo secret 掃描測試OpenClaw 日/週/月/Meta 長報告改為 GCP-A/GCP-B only不再讓 `openclaw_meta` 落到 111。
- 2026-06-05 起,`V10.600` 收斂 AI Intelligence 競品表前台標籤PChome 競品 footer 不再顯示 TTL / 比對門檻等工程參數,改顯示已通過身份比對的使用者語意;已知 matcher tag 轉成中文 badge未知 tag 隱藏,避免 raw internal tag 出現在營運畫面。
- 2026-06-05 起,`V10.599` 補全站巡檢降載與前端工作溝通隔離CONSTITUTION 新增第 14.2 條禁止把施工紀錄、版本發布說明、Codex/Claude 評估、推版語氣放進使用者可見頁面市場情報停用頁改為輕量產品狀態頁ICAIM dashboard API 增加短快取、stale fallback、5 秒 PostgreSQL statement timeout、LATERAL 最新價與最新 PChome identity row 查詢,避免全站巡檢與使用者開頁時被重查詢拖慢。
- 2026-06-04 起,`V10.578` 修正 Code Review deterministic scan 的 timeout 判定,多行 `requests.*(... timeout=...)` 不再被誤報為未設定 timeout。
- 2026-06-04 起,`V10.577` Code Review OpenClaw 會在 explicit Ollama host generate 前先做短 `/api/version` preflightGCP-A 不通時快速跳 GCP-B避免 15 秒 timeout 後才降級,且仍不呼叫 Gemini / 111。
- 2026-06-04 起,`V10.576` 修正 GCP-only Ollama retrycaller 禁用 111 fallback 時resolver 若回到 111 會改試 GCP-A/GCP-B allowlist不再讓 Hermes / Code Review 類任務因 resolver 快取到 111 而 `all 0 hosts failed`
- 2026-06-04 起,`V10.575` 拆分 PChome 型錄可比覆核 lane`catalog_comparable` 會依 diagnostic evidence 分成選項/色號、單位/入數與身份採用三條人工處理路徑Dashboard、decision envelope、coverage 與 Webcrumbs host data 使用同一套統計與 HITL guardrail。
- 2026-06-03 起,`V10.574` 新增市場情報 Source Governance → Fetch Target bridge`/api/market_intel/mcp_fetch_target_source_governance_review` 交叉審核 Professional Source Governance 與 MCP Fetch Target Review要求 target `platform_code/source_key` 全部命中已治理 source contract仍不抓外站、不讀 robots/sitemap、不開 DB、不寫檔、不執行 CLI、不掛 scheduler只放行到後續人工 fetch run package review。
- 2026-06-02 起,`V10.567` 將 MCP 市場洞察 fallback 收斂為 GCP-A / GCP-B only不再讓 111 承接非即時市場分析長任務;預設 timeout 25 秒、`num_predict` 500GCP 不可用時直接保守降級,避免 Elephant Alpha 60 秒 timeout 與 111 負載尖峰。
- 2026-06-02 起,`V10.568` 將價格類 `decision_envelope` 的 Telegram 直送訊息改為專業 brief標的、價格證據、比對證據、人工下一步四段式review queue 信封 subject 同步帶 `momo_price` / `competitor_price`,讓 Telegram、PPT、Webcrumbs 與 AI 摘要共用價格證據。
- 2026-06-02 起,`V10.569` 將 Webcrumbs host data 串到 `summarize_review_decision_envelopes()`payload 新增 `reviewDecisionBrief` 與 review queue / HITL / auto-execute-blocked metadata共用 UI runtime 讀同一份 PChome 覆核信封摘要,仍只讀 DB、不呼叫 LLM、不抓外站、不寫資料。
- 2026-06-15 起,`V10.605` 修正 PChome 後台業績 Excel 匯入韌性auto import 會掃所有 worksheet / 表頭列並選擇 `即時業績明細` 類明細 sheet欄位或日期不合格的檔案會移至 Drive `匯入失敗` 避免 30 分鐘重複告警;同版修復 scheduler 容器缺 `pg_dump` 的備份告警。Production 匯入任務 #54 成功寫入 12,460 筆,`daily_sales_snapshot``realtime_sales_monthly` 最新日期皆為 2026-06-14資料新鮮度 probe 降為 `gap=1 / info / notified=false`daily/growth chart runtime guard 通過。
- 2026-06-15 起,`V10.606` 正名為「PChome 業績成長自動化作戰系統」並新增只讀 `/api/ai/pchome-growth/opportunities`:作戰清單以 PChome 後台業績為主、MOMO 作為外部價格參考,蝦皮與酷澎先暫停且不進告警。正式只讀盤點確認 `daily_sales_snapshot."商品ID"``competitor_prices.competitor_product_id` 直接重疊為 0因此第一版不硬接 ID無可驗證對應時只輸出「先補商品對應」任務。AI 競情頁同步改成白話營運文案,避免把工程術語直接呈現給使用者。
## 3. 12 Agent 決策信封整合
- `decision_envelope` 已接到 NemoTron 價格告警與人工覆核,下一步要讓 OpenClaw、ElephantAlpha、PPT QA 與 review queue 共用同一份 evidence contract。
- 2026-05-24 22:44 CST 起EventRouter 對已附 `decision_envelope` 的事件直接渲染證據模板,不呼叫 L1/L2 AI handler這讓 NemoTron 價格告警、人工覆核與後續 Agent 共用同一份 SKU / PChome / evidence / guardrails不再二次生成摘要。
- 2026-05-24 23:00 CST 起,`fetch_competitor_review_queue()``fetch_competitor_review_queue_page()``/api/pchome-review/queue` 每筆候選也帶 `decision_envelope`,包含 SKU/PChome 標的、match evidence、人工下一步、預期價差與不可自動寫正式價差的 guardrailsDashboard、Agent、Telegram、PPT 後續共用此 contract。
- 2026-05-24 23:15 CST 起Dashboard 覆核卡與 PChome 覆核 Excel 匯出也顯示/輸出信封摘要、資料品質、HITL、trace、自動執行阻擋原因與證據摘要下載檔不得丟失 guardrails。
- 2026-05-24 23:25 CST 起OpenClaw 週報/日報/月報與 competitor PPT 使用 `summarize_review_decision_envelopes()` 的同一份 HITL 信封摘要,不再手寫 attempt_status 統計或自行翻譯覆核狀態。
- 2026-05-24 23:40 CST 起,`compare_existing_identity` 成為 `protected_existing_match` 的明確建議動作Agent 只能提示「比較既有正式候選與新候選」,不得因新候選分數較高自動寫正式價差。
- 2026-05-24 23:55 CST 起ElephantAlpha `resource_optimization` / `ea_escalation` 都必須帶 deterministic `decision_envelope`Telegram 按鈕 callback 使用 `decision_id`,證據只允許 action_plans、CPU 實測、hygiene 與 trigger trace。
- 告警不得再輸出空泛「預期效益」必須帶資料品質、證據來源、HITL 邊界與 trace id。
- Agent 建議只能輔助排序與分析,不得繞過 matcher / feeder / review service 寫正式價格。
## 3.1 Ollama / Embedding 健康
- 2026-05-25 08:48 CST 起,`OllamaService.generate_embedding(..., allow_111_fallback=False)` 若 resolver 回 111會強制改試尚未嘗試的 GCP-A/GCP-B不再讓背景 embedding 在 111 disabled 情境直接退出或只試單台 GCP-B111 仍不承接背景 `bge-m3`
- 2026-05-25 12:27 CST 起,背景 embedding 在 GCP-A/GCP-B 全掛時開啟短暫 failure circuit這是降載保護不代表 primary 已恢復。部署 smoke 時 GCP-B `/api/version` 已恢復 200下一步仍需恢復 GCP-A Ollama 或更新 110 的可用 SSH/GCP 操作憑證。
- 2026-05-25 12:37 CST 起,背景 embedding GCP-only failure circuit 改用 WARNING 記錄,避免可預期降級污染 ERROR 告警通道。
- 2026-05-25 13:35 CST 起GCP-B `bge-m3` 實測 P95 波動已超過 15s背景 embedding / host health model probe timeout 預設改 30s若 30s 仍常 timeout需進一步處理 GCP-B runner/CPU/模型併發,而不是再把 111 納入背景任務。
- 2026-05-25 14:10 CST 起GCP-A refused 已明確歸類為 infra blocker應用層不得改成 111 背景 fallback也不得把 110:11435 502 當成 momo-app 故障。背景 embedding 可依 `host_health_probes` 跳過近期 unhealthy GCP host但查 DB 必須 fail-open。
## 4. 業績分析資料與圖表修復
- 修正即時業績匯入 `snapshot_date text = date` 類型錯誤。
- PChome 後台業績匯出前半段仍需自動化:優先確認 PChome 後台是否支援排程寄信 / Email 附件 / FTP / API若無改做 110 或獨立 worker 的受控 browser 下載,再把檔案放進 Google Drive `當日業績匯入/`
- `/daily_sales``/growth_analysis` 圖表不得空白;需保留原本圖表並升級成更專業的呈現。
- 圖表需通過 runtime nonblank canvas 檢查與手機版 responsive。
- daily/growth/PPT 必須共用 `competitor_intel_repository` 的比價資料出口,避免價差方向或統計口徑分裂。
- 2026-05-24 23:55 CST 起daily/growth chart 判斷不再只看 series 長度;若序列全 0顯示 chart-empty 狀態而不是畫只有座標軸的假圖。正式 smoke 需跑 `scripts/check_sales_charts_runtime.js` 確認主要 canvas 非空。
## 5. PPT 視覺 QA 與自動簡報產線
- 每日、每週、每月、每季、半年、年度簡報需依排程產出。
- 每次產出與視覺 QA 結果必須完整寫入 DB。
- `/observability/ppt_audit_history` 必須清楚顯示 runtime 狀態、產出狀態、視覺 QA、問題追蹤與可預覽檔案。
- PPTX / PDF 預覽需可站內直接開啟,不能只下載。
- 2026-06-06 起,`V10.604` 修正定期簡報長期漏產:根因為 `schedule.run_pending()` 同步執行20:30/20:40/20:50 精準時段會被 feeder / AI 長任務卡過且不自動 replay。新增每 10 分鐘 missed-run catch-up、scheduler 背景化補跑、排程型市場情報與價格甜蜜點快速 fallbackproduction 已補齊 `daily``market_intel``price_elasticity`catch-up plan 顯示 daily/weekly/monthly/quarterly/half_yearly/annual 全數 ready`/observability/ppt_audit_history` 可看到新檔與預覽入口。
## 6. 外部 BI / 協作入口
- `/metabase` 不可空白,需顯示可診斷 bridge 狀態或可用替代入口。
- `/grist` / 資料協作連結不得連到其他專案站。
- 側欄與 topbar 外部工具入口要統一走 momo-pro bridge route。
## 7. AI 觀測台與全站 UI/UX
- 10 個 AI 觀測台頁面必須符合新版字體、字級、暖墨色、焦糖 accent、點陣視覺與 responsive 規範。
- 全站主要頁面需通過 desktop / mobile overflow guard。
- 表格與圖表只允許在局部容器橫向滾動,不可造成整頁無限延伸。
## 8. 效能與可觀測性
- 持續降低 `/daily_sales``/growth_analysis`、商品看板、PChome queue、PPT audit 首屏 TTFB。
- 避免 worker cold start 重查重算;必要時使用共享快取與指紋失效。
- 111 fallback 只作最後救急;持續監控 GCP-A / GCP-B / 111 用量與 circuit breaker。
## 9. 每輪收尾
- Focused tests → full pytest 或合理範圍回歸 → production smoke。
- 更新 SOT / memory / TODO。
- 推 Gitea正式部署確認 `/health` 版本。
- 記錄未完成與下一輪入口。
## 10. 2026-06-15 V10.607 外部市場來源正規化
- 新增 `external_market_sources` / `external_offers`,作為 MOMO、未來蝦皮、未來酷澎、供應商 API 與手動 CSV 的共同資料入口。
- `/api/ai/pchome-growth/source-contract` 提供只讀來源狀態與欄位 contractUI 只顯示白話狀態,例如「正在使用」「先暫停」「可用資料」。
- MOMO 目前先橋接既有已確認同款的比價快取;蝦皮與酷澎只保留 contract預設暫停、不進告警。
- 下一步:做手動 CSV 匯入 dry-run 與外部報價品質檢查頁,讓未來無論官方 API 或 provider API 都能先經過同一套品質門檻。
## 11. 2026-06-15 V10.608 外部報價 CSV 預檢
- 新增 `/api/ai/pchome-growth/external-offers/csv-dry-run`,接受 CSV 檔案或貼上的 CSV 文字,只做預檢、不寫 DB。
- AI 情報頁新增「外部報價預檢」區塊,顯示可使用、待確認、不能使用;用字保持白話,不顯示工程欄位給一般使用者。
- 預檢支援中文表頭例如「資料來源、外部商品ID、商品名稱、售價、資料時間、取得方式、PChome商品ID、同款狀態、資料可信度」。
- CSV 預檢是備援入口,不是日常主流程。
## 12. 2026-06-15 V10.609 外部報價自動同步
- 新增 `sync_legacy_momo_reference_offers()`,自動把已確認同款的既有比價快取同步進 `external_offers`
- 新增 `run_external_offer_sync_task`,每 4 小時自動執行;排在 competitor feeder 後,同步 MOMO 外部價格參考資料層。
- CSV 保留為 API / crawler / provider 故障時的救援預檢;日常目標是自動抓、自動同步、自動進作戰清單。
## 13. 2026-06-16 V10.610 PChome 作戰清單優先讀新資料層
- `/api/ai/pchome-growth/opportunities` 已改成優先讀 `external_offers`,只有缺資料時才 fallback 舊 `competitor_prices`
- `external_offers.raw_payload_json` 會保留舊比價快取中的 PChome 公開價,讓新資料層仍可算出 MOMO / PChome 價差。
- API stats 新增 `external_data_source_counts`,可看到「自動同步資料層」與「舊比價快取」各有多少筆。
- 下一步:把其他比價報表與 AI 告警逐步改讀 `external_offers`,讓 `competitor_prices` 降為 bridge/cache。
## 14. 2026-06-16 V10.611 作戰入口與資料來源可見化
- `/ai_intelligence` 是 PChome 業績成長自動化作戰系統的營運主入口V10.617 起舊「今日作戰入口」已改為「今日重點總覽」,首屏需先顯示下一步與今日處理清單,不再把備援 CSV 放在主要流程前段。
- PChome 成長作戰區塊會依 API stats 顯示今日優先動作,例如先補商品對應、先處理可直接比價商品,避免使用者只看到數字不知道下一步。
- 同區塊新增資料來源摘要,直接顯示「自動同步資料層」或「舊比價快取」各有多少筆,方便確認 V10.610 新資料層是否真的被作戰清單採用。
- CSV 預檢在 UI 文案上維持備援定位;日常主流程仍是自動同步外部報價。
## 15. 2026-06-16 V10.612 MOMO 外部價格參考優先讀新資料層
- `/api/ai/icaim/dashboard` 的「MOMO 外部價格參考」已改為優先使用 `external_offers`,同一 MOMO SKU 若有自動同步資料就不再先讀舊 `competitor_prices`
- 表格 stats 新增 `competitor_data_source_counts`,前端 footer 顯示「自動同步資料層 / 舊比價快取」各幾筆;每列狀態會顯示「自動同步」或「舊資料」。
- 價差與高風險統計改採 PChome 視角:正數代表 PChome 比 MOMO 外部參考價高,才列入需檢查價格。
- 下一步:把 Hermes / ElephantAlpha / AI product pick 等後端價格分析逐步改讀 `external_offers`,讓告警與頁面使用同一份資料來源。
## 16. 2026-06-16 V10.613 高可見頁面繁中化守門
- 使用者要求所有內容與頁面必須使用繁體中文工程內部變數、CSS class、API key 名稱可保留英文,但使用者可見標題、按鈕、狀態與說明不得用英文工程語。
- 已把 `/code-review/` 顯示文字改成「AI 程式碼審查」「流程進度」「程式碼審查完成」,並將 OpenClaw 模型顯示改成「Ollama 優先」,避免前台誤以為 Gemini 是主路徑。
- 已把 AI 自動化健康檢查頁改為白話繁中命名,狀態顯示改成「正常 / 注意 / 嚴重 / 產生時間」。
- 已把 PPT 觀測台與商品看板高可見英文標籤改成「產線健康度 / 工作隊列 / 視覺問題 / 產線控制台 / 覆蓋率流程」,並新增測試防回歸。
## 17. 2026-06-16 V10.614 部署與基礎設施頁繁中化
- `/cicd` 對使用者顯示為「部署監控」,不再以前台標題顯示 `CI/CD Dashboard`部署流程、部署歷史、GitLab 部署紀錄皆使用白話繁中。
- 部署流程圖會把後端階段代碼 `test / build / deploy` 轉成「測試 / 建置 / 部署」,診斷狀態也轉成「正常 / 注意 / 失敗」。
- `/observability/host_health` 與 PPT 產線視覺狀態把 `Runtime` / `Vision QA` 改成「執行環境」與「視覺檢查」,並更新測試防回歸。
## 18. 2026-06-16 V10.615 AI 智慧推薦頁 Ollama 主路徑文案
- `/ai_recommend` 的 AI 路徑顯示改成「Ollama 主路徑 / Gemini 備援」Gemini 選項保留為角色提示但停用手動選擇,避免使用者誤以為可直接用 Gemini 生成文案。
- `page-ai-recommend.js` 的狀態 badge、生成結果 meta、搜尋/分析錯誤訊息改用繁中全形冒號與「權杖」用語。
- 新增測試守門:禁止 `Ollama (本地)``Gemini (雲端)``Web Search``Token:` 與半形英文錯誤前綴回到 AI 智慧推薦頁。
## 19. 2026-06-16 V10.616 主商品看板統計標籤繁中化
- `/` 主商品看板補齊高可見統計標籤繁中化,將 `ACTIVE``PICK COUNT``AVG CONFIDENCE``EVIDENCE GAP` 等工程詞改為「有效商品」「挑品數」「平均信心」「待補證據」。
- PChome 補強區塊標籤改為「PChome 比價補強」,空狀態改為「目前有效商品沒有高優先 PChome 覆核項目」。
- 測試新增禁止英文工程標籤回歸,讓主商品看板符合「所有內容包含頁面皆為繁體中文」紅線。
## 20. 2026-06-16 V10.617 AI 情報頁改為作戰導向 UI
- `/ai_intelligence` 不再只堆說明文字;首屏新增「下一步」動態指令、商品處理進度、外部價格來源與操作捷徑。
- 今日處理清單改為表格,欄位優先呈現「優先級、建議動作、商品、近 7 天業績、比價結果、資料可信度、下一步」,讓使用者先看到該做什麼,以及資料能不能信。
- MOMO 外部價格參考新增價格風險分佈,表格改為 PChome 價格在前、MOMO 參考價在後價差明確顯示「PChome 貴 / PChome 便宜」,並新增「鎖定商品」操作。
- 備援 CSV 流程降級為「備援資料檢查」,移到主要作戰與價格表後面,避免誤導使用者以為日常仍要人工匯入。
- 前端補上 payload fallback、動態表格 escape、手機版 `data-label` 與補商品對應 busy lock避免資料缺欄位、特殊字元或重複點擊造成壞畫面。
## 21. 2026-06-16 V10.618 比價頁改為下一步導向
- `/price_comparison` 改為「PChome 商品比價決策台」,首屏需先顯示「今天先做」與 PChome / MOMO 商品準備狀態,不再讓使用者從 Step 1/2/3 自行猜流程。
- 頁面會依目前資料狀態切換下一步:輸入關鍵字、取得 PChome 商品、匯入 MOMO 商品、開始檢查價差、查看需檢查價格或可主推商品。
- 比價結果新增判讀分佈:「需檢查價格」「可主推曝光」「價格接近」,表格第一欄直接呈現每筆商品下一步。
- Toast 改用純文字 DOM手動輸入錯誤訊息不再塞 HTML更新商品資料時會清掉舊比價結果避免資料已更新但畫面仍顯示舊判讀。
## 22. 2026-06-16 V10.619 PChome 導向 MOMO 精準候選搜尋
- 使用者指出只抓 MOMO 活動頁會讓比價候選池偏窄V10.619 新增 `search_momo_products_for_pchome_products()`,用 PChome 商品名稱逐筆反查 MOMO 候選。
- 搜尋詞沿用 `marketplace_product_matcher.build_search_terms()`,保留品牌、品名、容量、單品與組合線索,例如 B5 40ml、500ml 2入組避免只用品牌或活動頁商品池。
- `/api/price_comparison/compare` 在已有 PChome 商品但缺 MOMO 清單時,會優先走 PChome 導向 MOMO 搜尋;完全沒有 PChome 商品時才退回品牌搜尋。
- MOMO 搜尋 parser 已補新版 Next.js `goodsInfoList`,避免明明搜尋頁有商品但 crawler 回 0 筆。
- `/price_comparison` 已新增「自動找 MOMO 候選」操作PChome 商品準備後可直接搜尋 MOMO回傳會分成「可直接比價」與「需人工確認」。
- 新路徑只擴大候選池,不放寬 `score_marketplace_match()` 的 hard veto 與同款分數篩選V10.619 當時先把 `unit_comparable` 候選保留為「需人工確認」,此限制已由 V10.620 的自動單位價分流取代。
## 23. 2026-06-16 V10.620 單位價候選自動化分流
- 使用者要求把需要人工處理的比價工作降到最低V10.620 將 PChome 導向 MOMO 搜尋的 `unit_comparable` 候選改成三路分流:同款總價、可自動換算單位價、真正需人工確認。
- `search_momo_products_for_pchome_products()` 會在 `unit_comparable` 時呼叫 `build_unit_price_comparison()`;只有能算出雙方總容量/數量、單位價與差距百分比時,才標成 `auto_compare_type=unit_price` 與「自動單位價比較」。
- `/api/price_comparison/fetch_momo_for_pchome` 回傳 `products``unit_compare_candidates``review_candidates` 三段;舊總價比價只吃 `products`,避免把組合包總價誤當同款價差。
- `/price_comparison` 顯示「同款 / 單位價 / 需確認」三個數量,並新增自動單位價面板;若只找到單位價候選,下一步會引導使用者查看單位價結果,而不是人工確認。
## 24. 2026-06-16 V10.621 自動候選接入外部價格參考
- `/price_comparison` 正常操作「自動找 MOMO 候選」時會帶 `sync_external_offers=true`,把可直接總價比價與自動單位價候選同步進 `external_offers`;仍需人工確認的候選不寫入。
- 新增 `sync_targeted_momo_candidates_to_external_offers()`,只寫 `ingestion_method='targeted_momo_search'``match_status='verified'``data_quality_status='verified'` 的安全候選;`unit_price` 候選會在 `raw_payload_json.unit_price_comparison` 保留 MOMO / PChome 單位價、容量/數量與價差百分比。
- `build_pchome_growth_opportunities()` 已能讀 `external_offers.raw_payload_json.price_basis='unit_price'`:作戰清單會顯示「資料可用單位價判斷」,並用單位價差距做「檢查售價與活動 / 放大價格優勢」判斷。
- 此路徑只同步外部價格參考與作戰清單,不寫 `competitor_prices`,不自動改價;目標是減少人工補資料,而不是放寬正式價差寫入。
## 25. 2026-06-16 V10.622 外部報價同步後即時刷新作戰清單
- 新增 `services/pchome_growth_cache_state.py`,以 `data/pchome_growth_cache_epoch.txt` 作為跨 Gunicorn worker 的作戰清單快取失效標記。
- `sync_legacy_momo_reference_offers()``sync_targeted_momo_candidates_to_external_offers()` 只要成功寫入 `external_offers`,就呼叫 `mark_pchome_growth_cache_stale()`
- `/api/ai/pchome-growth/opportunities` 的 in-memory cache 會記住建立時的 epoch讀快取前若發現共享 epoch 較新,會直接重建,不再讓使用者看到 120 秒舊清單。
- 這讓「自動找 MOMO 候選 → 同步外部價格參考 → AI 情報頁作戰清單」變成同一條即時資料流,減少使用者手動重新整理或等待快取過期。
## 26. 2026-06-16 V10.623 比價與作戰頁工作台化
- 使用者指出前端仍像文字堆疊無法快速知道怎麼操作V10.623 將 `/price_comparison` 第一屏改為主 KPI、目前卡點、四步流程與下一步 CTA。
- `/price_comparison` 的結果區新增決策摘要,先顯示「需檢查售價或活動 / 可主推曝光 / 觀察賣點」三類數字與建議,再往下看明細表。
- `/ai_intelligence` 第一屏新增今日任務摘要,直接顯示今日任務、可立即處理、待補比價與最新業績日;資料來自現有 PChome growth API stats。
- 測試守門新增 `priceDecisionGrid``price-workflow-strip``price-result-summary-grid``growth-executive-strip``renderGrowthExecutiveSummary`,避免頁面退回只有文字說明的狀態。
## 27. 2026-06-18 V10.624 ElephantAlpha 價格決策只進 HITL
- 部署後觀察到 `price_drop_alert` 進入 ElephantAlpha execution plan 後可能卡在 Hermes/NemoTron step最後以 60 秒 timeout 污染 scheduler log。
- V10.624 將價格類 trigger 的高信心路徑改為「有實證就發 L3 HITL 價格覆核通知」,不再執行 orchestrator `execution_plan`,避免長任務 timeout 與自動調價誤解。
- 新增 `price_decision_review` 決策信封,固定標示 `can_auto_execute=false``requires_hitl=true``execution_plan skipped`;通知只呈現 DB/Hermes 具體價差實證。
- 測試新增高信心價格決策不執行長任務 step 的守門,避免未來又把價格告警回退成自主執行。
## 28. 2026-06-18 V10.625 背景 embedding 熔斷不扣 retry
- 部署 V10.624 後 scheduler log 顯示 GCP-A 最近 host health 不健康GCP-B `bge-m3` 仍可能 30 秒 timeoutembedding worker 會在同批任務中連續把多筆 queue 標成失敗,造成 attempts 被白白消耗。
- V10.625 將 GCP embedding failure circuit 狀態公開為 `is_embedding_gcp_circuit_open()` / `embedding_gcp_circuit_remaining_seconds()`,讓 worker 可用明確狀態判斷,不再猜測空向量原因。
- `OpenClawLearningService` worker 在熔斷中不 claim 新任務;若處理中開啟熔斷,當筆與同批剩餘任務會退回 `pending` 並寫入延後原因,不扣 `attempts`、不刷成 `failed`
- 背景 embedding 仍維持 GCP-A → GCP-B不落 111111 不承接 `bge-m3` 背景批次的治理規則不變。
## 29. 2026-06-18 V10.626 GCP-A direct timeout 改走 110 proxy rescue
- 正式診斷腳本顯示188 直連 GCP-A `34.87.90.216:11434` `/api/version` timeout但 GCP-B direct、111、110 `11435` primary proxy、110 `11436` secondary proxy 都可用GCP-B `bge-m3` embed 實測約 2.9 秒。
- V10.626 新增 `OLLAMA_HOST_PRIMARY_PROXY` / `OLLAMA_HOST_SECONDARY_PROXY`,預設為 `http://192.168.0.110:11435` / `http://192.168.0.110:11436`
- `resolve_ollama_host()` 順序調整為 GCP-A direct → GCP-A via 110 proxy → GCP-B direct → GCP-B via 110 proxy → 111proxy rescue 是同順位入口救援,不代表 direct GCP host 已恢復。
- 近 24 小時 `ai_calls` 只有 `ollama_secondary=51``gcp_ollama=3``nim=1`,沒有 Gemini providerGemini hard disabled / fallback disabled 的紅線仍有效。
## 30. 2026-06-18 V10.627 Resolver 讀 host_health 跳過 direct timeout
- V10.626 已能在 GCP-A direct timeout 後走 110 proxy但 cache refresh 仍會先等一次 direct `/api/version` timeout。
- V10.627 新增 direct-only host health skip`resolve_ollama_host()` 會讀最近 `host_health_probes`,若 GCP-A/GCP-B direct 在視窗內已 unhealthy先跳過 direct endpoint改試同順位 110 proxyproxy rescue 不吃這個 skip避免因 direct unhealthy 誤跳過可用 proxy。
- 新增 `OLLAMA_RESOLVE_HOST_HEALTH_SKIP_ENABLED=true``OLLAMA_RESOLVE_HOST_HEALTH_SKIP_WINDOW_MINUTES=20`DB 讀取失敗 fail-open回到原本網路探測。
## 31. 2026-06-18 V10.628 備份 partial 檔案清理
- 正式 `backup_log` 最新狀態已是 2026-06-18 02:00 成功備份6/15 的 `pg_dump` not found 是舊失敗紀錄;`get_latest_backup_info()` 目前回 successbackup monitor 不會再因舊 row 告警。
- 備份目錄仍殘留 0 byte `momo_analytics_*.sql.gz` partial 檔,容易讓人工查檔誤判。
- V10.628 新增 `cleanup_partial_backups()``cleanup_old_backups()` 會先清除超過 `PARTIAL_BACKUP_MIN_AGE_MINUTES=60` 的 0 byte partial 備份;剛產生的 0 byte 檔不刪,避免誤傷正在寫入的備份。

View File

@@ -0,0 +1,175 @@
# Frontend V3 Handoff 2026-05-12
## 目的
這份 handoff 給下一個 Codex session 接續「前端 V3 全站 UI/UX 與響應式修正」使用。
## 已完成
- 已閱讀並遵守專案入口規則:`AGENTS.md``CONSTITUTION.md`、ADR-011 部署紅線、部署 SOP。
- 已評估 Claude Code 的「立刻 Flask → FastAPI」建議結論改為
- FastAPI 可作為 strangler migration 中期方向。
- 不作為前端 V3 落地前置條件。
- 不做大爆炸式後端重寫。
- 已新增 `docs/adr/ADR-036-fastapi-strangler-not-frontend-prerequisite.md`,並更新 `docs/adr/README.md`
- 已把 V3 shell/tokens/page assets 落到 Flask runtime
- `templates/ewoooc_base.html`
- `templates/components/_ewoooc_shell.html`
- `web/static/css/ewoooc-tokens.css`
- `web/static/css/ewoooc-shell.css`
- `web/static/css/ewoooc-dotmatrix.css`
- `web/static/css/ewoooc-tokens-v2-alias.css`
- 多個 `web/static/css/page-*.css`
- 多個 `web/static/js/page-*.js`
- 已保留真實功能頁,拒絕直接用 `production_v3 3/templates/dashboard.html` 與 observability prototype 覆蓋正式頁,因為會移除 PChome、AI 挑品、歷史價格、觀測台真實資料。
- 已修 `/sales_analysis` 首次進頁錯誤:
- `routes/sales_routes.py``category_data=cat_data`
- `templates/sales_analysis.html` 對 chart JSON payload 補 default fallback避免 Jinja `Undefined``tojson`
- 已同步版本:
- `app.py` `SYSTEM_VERSION = "V10.91"`
- `config.py` `SYSTEM_VERSION = "V10.91"`
- 已更新 `TODO_NEXT_STEPS.txt`,記錄 V3 守門落地、正式推版與後續 FastAPI inventory。
## 已部署到正式環境
- 正式 URL`https://mo.wooo.work`
- 部署方式:白名單 tarball 同步 55 個 V3 runtime 檔案,再單獨同步 `config.py`
- 正式端只 recreate `momo-app`
- `docker compose up -d --no-deps --force-recreate momo-app`
- 未碰 `momo-db`
- 未使用 `--remove-orphans`
- 正式回滾備份:
- runtime files`/tmp/codex_v3_predeploy_20260512_144835.tgz`
- config`/tmp/config.py.pre_v3_20260512_145111`
## 已通過驗證
- 本機 focused pytest`75 passed, 1 warning`
- `git diff --check` 通過。
- `./scripts/quick_review.sh --check-observability-css` 通過。
- `./scripts/quick_review.sh --observability-ui` 通過。
- `./scripts/quick_review.sh --observability-qa --skip-production` 通過。
- 正式:
- `https://mo.wooo.work/health` 回報 `V10.91`
- `momo-pro-system``momo-scheduler``momo-telegram-bot``momo-db` 全部 healthy。
- `./scripts/quick_review.sh --observability-qa --base-url https://mo.wooo.work` 通過。
- V3 smoke 200`/sales_analysis``/daily_sales``/monthly_summary_analysis``/ai_recommend``/auto_import``/vendor-stockout/*``/growth_analysis``/settings``/logs``/`
## 2026-05-12 V10.92 追更
- 已完成 `/daily_sales` 本機 route 驗證與 responsive 修正。
- 已完成 `/edm` 桌機外溢與 mobile responsive containment 修正。
- 已將 V3 內容最大寬度調整為 `1600px`,改善寬螢幕活動頁與資料表使用空間。
- 已移除 V3 主要頁面 CSS 中殘留的負字距。
- 已新增全頁 responsive overflow 自動化:
- `scripts/check_v3_responsive_ui.js`
- 本機全頁 responsive audit 已通過,覆蓋 23 個主要 routedesktop 1440 與 mobile 390 共 46 項皆 PASS。
- 本機 observability QA 已通過:
- focused pytest `75 passed, 1 warning`
- `git diff --check`
- `scripts/check_v3_responsive_ui.js`
- 已白名單部署到正式環境 `https://mo.wooo.work`,版本升至 `V10.92`
- 正式端只 recreate `momo-app`
- `docker compose up -d --no-deps --force-recreate momo-app`
- 未碰 `momo-db`,未使用 `--remove-orphans`
- 正式回滾備份:
- `/tmp/codex_v3_1092_predeploy_20260512_164549.tgz`
- 正式驗證已通過:
- `/health` 回報 `V10.92`
- `momo-pro-system``momo-scheduler``momo-telegram-bot``momo-db` 全部 healthy。
- `scripts/check_v3_responsive_ui.js``https://mo.wooo.work` 通過23 route × desktop/mobile = 46/46 PASS。
- `./scripts/quick_review.sh --observability-qa --base-url https://mo.wooo.work` 通過。
## 2026-05-13 V10.115 main 追更
- main 已補 AI 觀測台 V3 responsive / overflow 守門:
- `scripts/check_responsive_overflow.js` 會把 visual overflow offenders 視為失敗。
- 表格與圖表允許在 `.obs-table-shell``.obs-chart-frame` 等局部容器內滾動,避免整頁水平外溢。
- `observability-system.css` 與 Flask mirror `web/static/css/observability-system.css` 已同步補強:
- bounded table/chart/mobile containment。
- badge / pill / nested surface 對比規範。
- hero / panel 密度收斂,避免 inline legacy template 保留裝飾空白。
- 本機 QA 已通過:
- `python3 scripts/sync_observability_css.py --check`
- `./scripts/quick_review.sh --observability-ui`
- `./scripts/quick_review.sh --observability-qa --skip-production`
- focused frontend / Phase 3f pytest。
- 本段只記錄 main repo 推版與本機 QA未在本段宣稱正式環境已完成 V10.115 部署驗證。
## 2026-05-13 V10.116 main 追更
- main 已補 AI 觀測台 rendered visual contract
- `scripts/check_observability_visual_contract.js`
- `scripts/check_observability_visual_contract.sh`
- `./scripts/quick_review.sh --observability-visual`
- `scripts/check_observability_suite.sh` 在 production smoke 後有第 4 步;`--skip-production` 時會明確 skip rendered visual contract。
- 觀測台手機密度與商業情報頁 title/chip 對比已補強,`templates/admin/business_intel.html` 的 H1 已有 `biz-title` classV10.116 main 版的 local rendered contract 已覆蓋 10 頁 × desktop/tablet/mobile 30 項 PASS。
- 本機 SQLite visual QA 曾因 `/observability/host_health` GET 頁嘗試寫 `host_health_probes` 而噴 BIGINT autoincrement warningmain 已改為 SQLite session 下略過 probe persistence正式 Postgres 路徑仍保留寫入。
- 本段只記錄 main repo 推版與本機 QA未在本段宣稱正式環境已完成 V10.116 部署驗證。
## 2026-05-13 V10.117 main 追更
- AI 觀測台已改成 tokenized dot-matrix 背景語彙,`scripts/check_observability_visual_contract.js` 會檢查 hero/signal/panel surface 的 rendered `background-image` 必須是 `radial-gradient`,並防止 legacy `linear-gradient``background-image: none` 回流。
- `static/css/observability-system.css` 檔尾保留 terminal dot-matrix layer不要把它移回 v3.4/v3.5 neutralizer 之前,否則 computed style 會被後段 `background-image: none !important` 覆蓋。
- 本機 `http://127.0.0.1:5017` 已重跑 rendered visual contract10 頁 × desktop/tablet/mobile 共 30 項 PASS。
## 重要使用提醒
- 不要用 `file://.../templates/*.html` 預覽 Jinja 模板。它需要 Flask route 注入 `url_for()`、context 與 session。
- 正確本機預覽方式:
- 啟動 Flask`LOGIN_PASSWORD=codex-local-password SECRET_KEY=codex-local-secret USE_POSTGRESQL=false .venv/bin/flask --app app:app run --host 127.0.0.1 --port 5003`
- 用瀏覽器開:`http://127.0.0.1:5003/daily_sales``http://127.0.0.1:5003/edm` 等 route。
- 使用 Browser plugin 時,應導到 localhost route不要開 template 檔。
## 未完成
- 使用者指出「很多頁面排版都有問題,且必須全部確認手機版」。
- `/daily_sales``/edm`、全頁 responsive overflow 自動化與 V10.92 正式部署已完成。
- 尚未完成所有頁面的人工 desktop/mobile 視覺逐頁設計審查;目前完成的是自動化 overflow guard 與重點頁抽看。
- 若下一輪繼續 UI/UX建議從「自動化已過但人工視覺仍需精修」的頁面開始例如長表格密度、空狀態、文案層級與 mobile 互動細節。
## 下一個 session 建議順序
1. 啟動本機 Flask server導 in-app browser 到目標 route。
2. 用 desktop 與 mobile 寬度檢查:
- 1365/1440 desktop
- 390 mobile
- 不得有 body horizontal overflow。
- text 不得重疊或被裁切。
- 表格/日曆若需要橫向滾動,必須有明確容器與提示,不能讓整頁外溢。
3. 每輪 UI 變更後跑全頁 responsive overflow guard`scripts/check_v3_responsive_ui.js`,至少覆蓋:
- `/`
- `/edm`
- `/sales_analysis`
- `/daily_sales`
- `/monthly_summary_analysis`
- `/growth_analysis`
- `/ai_recommend`
- `/auto_import`
- `/vendor-stockout/`
- `/vendor-stockout/import`
- `/vendor-stockout/list`
- `/settings`
- `/logs`
- `/observability/*` 10 頁
4. 全頁本機 QA 通過後,才按部署 SOP 白名單同步正式。
## 當前工作樹注意事項
- 工作樹很髒,混有多批未提交變更與大量 untracked 原型/文件/前端資料夾。
- 不要整包 rsync 或整包 commit。
- 不要 revert 使用者或其他 session 的變更。
- 部署只能用白名單。
- 特別避免同步:
- `.claude/`
- `production_v3*/`
- `frontend/`
- `MOMO Pro/uploads/`
- `data/dashboard_full_cache.pkl`
- 未確認的 docs/design dump
## 已知本機/正式 warning
- 本機 Python 3.9 / LibreSSL 會有 urllib3 warning。
- 本機 SQLite 缺 `embedding_retry_queue` 時 OCLearn worker 會 warning。
- 正式 compose 會警告 `momo-db` orphan這是 ADR-011 已知狀態,禁止 `--remove-orphans`

View File

@@ -12,6 +12,307 @@
## 📅 詳細更新日誌 (考古存檔)
### 2026-06-01PChome 比價新鮮度操作閉環
- **V10.601 Gemini / 111 治理收斂與全 repo 已知密鑰清除**: 正式 `ai_calls` 近 24 小時與近 7 天 provider 彙總確認沒有 Gemini 出站Gemini 仍由 `GEMINI_API_HARD_DISABLED=true``GEMINI_FALLBACK_ENABLED=false` 擋住。清除舊 K8s manifest、n8n workflow、監控/auto-repair scripts、Superset 文件、Google Drive token 檔與歷史文件中的已知實密鑰,改成占位符並新增 secret 掃描測試OpenClaw 日/週/月/Meta 等敘事長報告改為 GCP-A/GCP-B only不再讓 `openclaw_meta` fallback 到 111 承接長文生成。
- **V10.600 AI Intelligence 競品表前台標籤收斂**: PChome 競品表 footer 改為使用者可理解的身份比對說明,不再顯示 TTL 與全域門檻等工程參數。前端 tag renderer 只把 `identity_v2``match_type_exact``price_alert_exact``evidence_*``match_*` 等已知 matcher 診斷轉成中文 badge未知內部 tag 不顯示,避免把 raw matcher code 暴露到營運畫面。
- **V10.599 全站巡檢降載與前端工作溝通隔離**: 新增 CONSTITUTION 第 14.2 條禁止把施工紀錄、版本發布說明、AI 工作視窗判斷、Codex/Claude 評估或 Gitea 推版語氣放進使用者可見前端頁面。市場情報停用頁改成輕量產品狀態頁,移除 `system_version` 與工程文案ICAIM 競情 dashboard API 新增 120 秒快取、900 秒 stale fallback、PostgreSQL 5 秒 statement timeout、LATERAL 最新價查詢與 DISTINCT ON 最新 PChome identity row避免全站巡檢或使用者開頁時被重型查詢拖慢。
- **V10.584 PChome Nick 去重 + stale recovery 單品窄門**: PChome `Nick` 進 matcher 前會去除 HTML 標籤、星號行銷文與重複品名,避免同一個 `29g / 100ml` 被副標重複計數後誤判 `component_count_conflict`。依 10 筆正式 stale recovery 診斷,新增 NIVEA 妮維雅霜 100ml、Schick 舒綺敏感肌除毛刀片 3 入、TS6 沁涼潔淨慕斯 100g 的具名 exact total-price alignmentIBL 沐浴精+洗髮精 vs 洗髮精、唇釉色號目錄款、Paula's Choice 效期/金蓋差異仍維持 identity review。
- **V10.583 Paula's Choice 身體乳 PChome Nick 具名 alignment**: matcher 新增 Paula's Choice `2%水楊酸身體乳210ml二入` 的窄範圍 alignment讓 PChome `Nick` 補出的 `水楊酸身體乳雙入組 / 210ml x2` 可和 MOMO 品名對齊並進 `exact / total_price / price_alert_exact`。此版不泛用放寬中文入數;`118ml二入組(金蓋限定版)` 對上 PChome 效期品仍維持 `manual_review / identity_review`,不寫正式價差。
- **V10.582 PChome 比價通知專業分級 + Nick 副標身份證據**: NemoTron 價格決策信封補齊 `momo_price``competitor_price``candidate_gap_pct``sales_7d_delta_pct`,避免 EventRouter / Telegram 模板拿不到核心價格事實。價格決策模板新增「通知分級」,將 `match_type / price_basis / alert_tier` 翻成直接價格威脅、單位價覆核、身份覆核或壓制告警,並同步顯示操作邊界;單位價或 identity 未確認時明確禁止以總價直接判定價格威脅。PChome crawler 另保留 `Nick` 副標為 `match_name` 給 matcher 使用UI/DB 顯示仍用原品名,讓容量、入數、濃度資訊可參與比對。
- **V10.581 重複單品組 retryable revalidation 接線**: 將 V10.580 的安全 matcher 線接到 `run_retryable_candidate_revalidation()`,但只收 `true_low_confidence` 中舊診斷已是 `match_type=exact / price_basis=manual_review`、沒有 review block且命中具名安全商品線的候選。這讓 Bioneo / Cetaphil / Avene / Schick / KOSE 等重複單品組可以小批次重評並由最新版 matcher 決定是否寫入正式 `competitor_prices`,仍不開放泛用高分掃描。
- **V10.580 PChome 重複單品組 total-price 窄門 + 核心油種 veto**: matcher 將同品牌、同入數、同基礎規格且名稱高度對齊的重複單品組,從 `exact / manual_review` 收斂到 `exact / total_price / price_alert_exact`;正式部署前以最新 `true_low_confidence` 重算213 筆高分候選中僅 7 筆符合自動寫入安全條件。同步新增 NEW DIRECTIONS 甜杏仁油 vs 杏桃核仁油 hard veto避免同容量同按壓頭但核心油種不同的候選被誤放行PChome 端缺規格的 Paula's Choice 雙入組仍停在 manual review。
- **V10.579 PChome 高信心 total-price safe family + Code Review timeout 收斂**: matcher 新增 SAB 私密防護舒緩噴霧 30ml 與 Herbacin 小甘菊 20ml 護手霜的窄範圍 total-price safe 路徑。這些候選仍必須通過既有 score、hard veto、variant/commercial gap 與 overwrite protectionHerbacin 柔皙 vs 野生玫瑰跨 variant 反測維持不進正式價差。目的在不放寬 `MIN_MATCH_SCORE` 的前提下,把可證明同款的高信心 `true_low_confidence` 轉進正式比價覆蓋。同版將 Code Review GCP-B secondary timeout 預設由 60 秒收斂到 25 秒GCP-A preflight 不通且 GCP-B 生成卡住時更快回 deterministic local degraded不呼叫 Gemini/111。
- **V10.578 Code Review 靜態掃描 timeout 誤報修正**: Hermes deterministic scan 對 `requests.get/post/put/delete/patch` 改檢查同一呼叫 block 的後續行,已在多行呼叫中帶 `timeout=` 時不再報「HTTP request 未設定 timeout」。這修掉 V10.577 preflight helper 被 Code Review 自己誤判為 MEDIUM 的噪音。
- **V10.577 Code Review Ollama host preflight**: OpenClaw 架構評估在 explicit GCP host generate 前先以短 `/api/version` 探測健康度;若 GCP-A 從 188 連線 timeout會快速跳到 GCP-B `gemma3:4b`,避免每次等 primary generate timeout。此 preflight 只作用於 Code Review Ollama-first 路徑,仍維持 111 預設禁用、Gemini hard-disabled 預設不呼叫。
- **V10.576 PChome backlog lane 與 GCP-only Ollama retry 修補**: `/api/ai/pchome-match/backfill/status` 的 coverage 與 operation backlog 同步輸出 `catalog_variant_review``catalog_unit_review``catalog_identity_review`,讓 Dashboard 操作建議可直接跳到三條人工隊列。同版修正 `OllamaService.generate(allow_111_fallback=False)`:若 resolver 已快取到 111會改試尚未嘗試的 GCP-A/GCP-B allowlist不再直接 `all 0 hosts failed`,同時仍避免長分析落到 111。
- **V10.575 PChome 型錄可比覆核 lane 分流**: `catalog_comparable` 進一步拆成 `catalog_variant_review``catalog_unit_review``catalog_identity_review`。Coverage SQL、review queue filter、Dashboard 分段、decision envelope 與 Webcrumbs host data 共用同一套 helper將選項/色號/款式、入數/商業條件、身份採用三種人工閉環路徑分開統計與瀏覽;仍維持 HITL不自動寫正式價差。
- **V10.574 PChome 型錄/任選可比覆核隊列**: 將 V10.572 的 `catalog_comparable_count` 派生口徑正式接進 PChome review queue。高分、無 hard veto、具同品線身份證據但仍有任選/型錄/商業條件待確認的 `true_low_confidence` 會進獨立 `catalog_comparable` 篩選、狀態標籤與 decision envelope真正 `true_low_confidence` 會排除這批候選,避免重複出現在「證據不足」。此變更不放寬 `MIN_MATCH_SCORE`、不寫正式 `competitor_prices`、不算 exact matched只把最有機會人工批次確認的候選變成可操作隊列。
- **V10.574 市場情報 Source Governance → Fetch Target bridge**: 新增 `/api/market_intel/mcp_fetch_target_source_governance_review`、preview service 與市場情報頁 bridge panel交叉審核 Professional Source Governance 與 MCP Fetch Target Review。此 gate 要求每個 target `platform_code/source_key` 都能對上已通過治理的公開 source contract並同步納入 deployment readiness preview-safe check 與 production smoke targetAPI/UI 仍不抓外站、不讀 robots/sitemap、不開 DB、不寫檔、不執行 CLI、不掛 scheduler。
- **V10.572 PChome 決策支援覆蓋率分層**: 覆蓋率不再只有 exact `decision_ready_rate``fetch_competitor_coverage()` cache 升到 v11新增 `catalog_comparable_count``decision_support_count``decision_support_rate` 與非 exact 支援數;只納入高分、無 hard veto、同時具型錄/任選/商業條件訊號與強身份證據且排除品類、品線、入數、香味、型號、價格極端等硬衝突的候選。Dashboard、daily、growth 與 backfill JS 同步顯示「決策支援覆蓋率 / 精準可告警覆蓋 / 型錄可比 / 單位價」,提升可用情報覆蓋但不污染正式 `matched`
- **V10.571 PChome pending 覆蓋率搜尋召回**: `competitor_price_feeder` 預設每個商品最多搜尋詞由 5 組提升為 6 組,並新增 `PCHOME_FEEDER_SEARCH_COVERAGE_RESCUE_ENABLED`。補抓流程會在主要 matcher 搜尋詞與原始名稱 fallback 之間加入狹義 coverage rescue terms保留 `5.5g` / `2.4g` 等小數規格,並過濾外出清潔、卸除髒汙、卸防曬等非身份核心噪音。正式 pilot 顯示 CeraVe / TUNEMAKERS / Embryolisse / Neogence / NIVEA 這類雙語品牌商品常卡在 PChome 搜尋召回,因此補上「英文品牌 + 中文品牌 + 核心身份 + 規格」窄搜尋詞;`品牌 + 品類 + 規格` 仍只對安全品類開放,目標是提升 pending/no_result 候選取得率,同時維持 matcher hard veto 與 `MIN_MATCH_SCORE` 不變。
- **V10.570 PChome 身份 / 報價證據契約**: `score_marketplace_match()` 現在會在 `match_diagnostic_json` 內輸出 `identity_evidence``offer_evidence`把品牌、品類、identity anchor、型號、規格、入數、variant guardrail 與價格 offer 拆層保存。`competitor_intel_repository` 會把這些證據轉成 `difference_highlights` 與 decision envelope 的 identity / offer evidence讓覆核頁、PPT、OpenClaw、Webcrumbs 與 Telegram 摘要都能理解「為何同款 / 為何不同 / 價格只是報價證據不是身份證據」。
- **V10.569 Webcrumbs 比價信封摘要串接**: `build_webcrumbs_marketplace_host_data()` 讀取 `fetch_competitor_review_queue()` 後統一走 `summarize_review_decision_envelopes()`,在 host data payload 輸出 `reviewDecisionBrief`,並於 metadata 增加 `review_queue_count``hitl_count``auto_execute_blocked_count``decision_envelope_source`。Webcrumbs / Shared UI 現在和 Telegram、OpenClaw、PPT 共用同一份 PChome 覆核信封摘要,仍維持只讀、不呼叫 LLM、不抓外站、不寫 DB同版收錄 `docs/guides/external_professional_benchmark.md` 作為外部專業做法週巡檢落地準則入口。
- **V10.568 價格類決策信封專業 brief**: `decision_envelope` 的價格 / PChome 覆核事件在 Telegram EventRouter 直送時,改以「標的、價格證據、比對證據、人工下一步」四段式排版呈現,保留 `momo:eig:` 忽略按鈕且不進 L1/L2 AI 重摘要。`competitor_intel_repository` 同步在 review queue 信封 subject 補上 `momo_price` / `competitor_price`,讓 Telegram、PPT、Webcrumbs 與 AI 摘要可共用同一份價格證據,不再各自補查或重組。
- **V10.567 MCP 市場洞察 GCP-only fallback**: `MCPCollectorService._ollama_topic_fallback()` 改成只使用 GCP-A / GCP-B Ollama失敗後保守回本地 fallback不再把市場洞察長分析轉嫁到 111。預設 timeout 收斂為 25 秒、`num_predict` 收斂為 500避免 Elephant Alpha 在 GCP-A/GCP-B 短暫不可用時撞 60 秒總上限或造成 111 負載尖峰Gemini 仍維持 `GEMINI_API_HARD_DISABLED=true` 預設硬封鎖。
- **V10.565 PChome 覆蓋率操作建議**: 補強 `/api/ai/pchome-match/backfill/status`,將低覆蓋率拆成 `operation_backlog`:刷新舊 identity、重評近門檻、補抓未配對、人工覆核、單位價覆核與過期搜尋救援預覽並新增 `recommended_next_action`Dashboard 狀態摘要會直接顯示建議下一步,避免使用者只看到低覆蓋率卻不知道該按哪條產線。
- **V10.563 正式 preview 假可救候選收斂**: 針對正式 `retryable_candidate_preview` 露出的 M.A.C 蜜粉與 SAUGELLA 菁萃潔浴凝露案例補 guard。M.A.C 單邊明確色號(如 `#絕絕紫`)會進 `variant_selection_review`,維持 `true_low_confidence`SAUGELLA 潤澤 / 日用型 / 加強 / 黃金女郎型互斥,直接 hard veto避免同品線不同私密清潔款式被當成 recoverable low_score。
- **V10.566 市場情報 Professional Source Governance**: 新增 `/api/market_intel/mcp_professional_source_governance`、preview service/gates/sample 與市場情報頁卡片,將 robots/REP、sitemap/lastmod、JSON-LD / schema.org structured data、canonical URL、rate limit、公開資料邊界、provenance、snapshot hash 與 idempotency key 納入 source contract。此 gate 只審核操作員治理摘要,不抓外站、不讀 robots/sitemap、不開 DB、不寫檔、不掛 schedulerdeployment readiness 同步新增 preview-safe 檢查與 production smoke target。
- **V10.561 PChome 比價補強前端分段回饋**: Dashboard 的 PChome 操作卡改名為「比價補強產線」,手動按鈕與確認文案同步說明三段流程;結果摘要會顯示刷新、重評、補抓各自的 matched/total讓操作員能判斷覆蓋率改善來自舊 identity 新鮮度回補、近門檻 matcher 回刷,或 pending 商品 fresh search 補抓。
- **V10.560 手動 PChome 比價補強三段式串接**: `/api/ai/pchome-match/backfill` 與每日 scheduler 口徑對齊,手動執行時先小批次刷新過期 `identity_v2`,再跑近門檻候選重評,最後補抓高優先未配對商品。回傳結果新增 `stale_identity_refresh` 分段統計,讓後續 Dashboard、簡報與 AI 決策能區分覆蓋率改善來自舊 identity 新鮮度回補、matcher 回刷,還是 fresh search 補抓。
- **V10.559 retryable 有效身份新鮮度收斂**: `_fetch_retryable_candidate_skus()` 的既有 identity 阻擋條件改成只接受 `cp.expires_at > CURRENT_TIMESTAMP`,不再讓 `expires_at IS NULL` 的未知新鮮度舊配對壓住近門檻候選回刷。未知新鮮度仍由 expired identity refresh / recovery 路徑處理,最後寫入仍必須通過現行 matcher、hard-veto、auto write safety 與 stronger existing production match 保護。
- **V10.558 legacy focused identity reason 回刷補漏**: `_fetch_retryable_candidate_skus()` 在 V10.557 的具名 identity guard 之外,補上歷史資料缺 marker 的情境:舊 attempt 若沒有新版 `focused_exact_total_price_safe`,但已有具名 `focused_exact_identity_*` 且該 identity 屬於 matcher total-price safe set並且舊分數已達全域 `MIN_MATCH_SCORE`,可進近門檻重評。仍要求無 hard veto、`exact_identity`、無 commercial / variant / count / bundle 阻擋,最後由最新版 matcher 決定是否能寫正式價差。
- **V10.557 focused reason-based 回刷具名 identity guard**: V10.555 的結構化 reason 回刷再收緊,`_fetch_retryable_candidate_skus()` 不只要求 `focused_exact_total_price_safe`,還必須同時命中一條具名 `focused_exact_identity_*` 且該 identity 來自 matcher 的 total-price safe set。這避免只有總開關、缺少身份線索的舊 attempt 被納入回刷rom&nd、Solone、Summers Eve 等 review-only focused line 仍被測試鎖在自動價差線外。
- **V10.556 GCP-B model fallback 防 111 過載**: `OllamaService.generate()` 現在會在 GCP-B 對 coder/large 模型使用 host-compatible fallback預設 `gemma3:4b`),避免 GCP-B 缺 `qwen2.5-coder:7b` 時直接被標成 unhealthy 並把流量推到 111。HTTP 404 且訊息為 model not found 時視為模型缺失,不再 mark 整台 host unhealthy其他 HTTP / timeout 仍照舊標 unhealthy。主機順序仍是 GCP-A → GCP-B → 111。
- **V10.555 focused total-price reason-based 回刷窄門**: `_fetch_retryable_candidate_skus()` 新增結構化 diagnostics reason 回刷入口,舊 attempt 若已帶 `focused_exact_total_price_safe` 且命中 matcher 的 `FOCUSED_IDENTITY_TOTAL_PRICE_REASONS`,即可進近門檻重評,不再完全依賴手寫商品名 SQL。此路徑仍要求分數下限、無 hard veto、`exact_identity`,並套用 commercial / variant / count / bundle 等阻擋理由rom&nd、Solone、Summers Eve 等 review-only focused line 不在 total-price reason set仍不會被推入自動價差。
- **V10.554 香氛 / 精油 focused exact 回刷接線**: Herb24 晨霧純精油擴香儀黑色、Pavaruni 40 香味 10ml 精油、Pavaruni 20 香味 450g 香氛蠟燭、Derma 大地有機植萃護膚油 150ml 已明確列入 matcher 的 `focused_exact_total_price_safe`,並接入 `_fetch_retryable_candidate_skus()` 的近門檻舊候選回刷入口。SQL 仍要求 `low_score / refresh_low_score / true_low_confidence`、分數下限、無 hard veto、`exact_identity`且排除變體、商業條件與件數衝突Laundrin、好物良品融蠟燈、Yuskin 等帶人工覆核訊號的品線不納入本輪自動回刷。
- **V10.553 current PPT/AI 比價結果查詢瘦身**: `fetch_competitor_comparison_results()` 不再用 `ROW_NUMBER() OVER (PARTITION BY p.id ...)``price_records` 取得 current/latest MOMO 價格,改為 `JOIN LATERAL` 逐商品取最新價;有指定 `end_date` 的歷史報表仍把 `pr.timestamp < DATE(:end_date) + INTERVAL '1 day'` 放在 lateral 子查詢中,保留「截止日前最新 MOMO 價」語意。這降低簡報、OpenClaw/AI payload 與比價匯出在大量價格紀錄下的查詢成本。
- **V10.552 決策查詢新鮮度口徑收斂**: Top competitor risks、PChome review queue、review sample 與 current PPT/AI 比價結果全部改成只吃 `cp.expires_at > CURRENT_TIMESTAMP` 的有效 PChome identity_v2 價格,不再把 `expires_at IS NULL` 當作有效現價。未知新鮮度現在只作 coverage 診斷與刷新入口不會被用來產生價格風險、簡報、AI 決策或從覆核隊列中排除。
- **V10.551 未知新鮮度刷新與補抓排序收斂**: `expires_at IS NULL` 的 identity_v2 價格現在會被 `_fetch_expired_identity_skus()``_fetch_expired_identity_recovery_skus()` 視為需要刷新 / 可搜尋救援的未知新鮮度資料,避免 V10.549 已排除出可決策覆蓋率後卻沒有刷新入口;兩條路徑都改用 `JOIN LATERAL` 取最新 MOMO 價,不再做 product-wide window scan。`_fetch_unmatched_priority_skus()` 同步改為 lateral latest price且把低風險 `no_result / refresh_no_result` 排到補抓前段,讓安全召回詞優先投入最可能回收的 SKU。
- **V10.550 安全搜尋召回詞補強**: `competitor_price_feeder` 在既有精準搜尋詞之外,對低風險穩定品類補上一組 `品牌 + 品類` recall keyword提升 `no_result / refresh_no_result` 找到候選的機率;高 variant 風險商品如美甲片、指甲油、唇彩、香氛/精油、粉底、防曬與含任選/色號/款式/香味的商品不走通用召回。DASHING DIVA 仍保留既有 line-specific recall 與 PChome sort fallback本次不更動 `MIN_MATCH_SCORE`、hard veto、auto write safety 或 stronger existing match 保護。
- **V10.549 比價新鮮度 KPI 口徑收斂**: `fetch_competitor_coverage()` cache 升到 v10`expires_at IS NULL` 不再混入 `fresh_matches` / `decision_ready_rate`,改拆成 `unknown_freshness_matches``unknown_freshness_rate`,讓「可用比價覆蓋率」只代表有明確未過期時間的 identity 價格。Dashboard、daily、growth 同步顯示未知新鮮度與「未形成有效身份配對」,第一屏資料時間改看最新有效 PChome 價格抓取,並把價格方向文案改為 `PChome 價格壓力` / `MOMO 價格優勢`
- **V10.548 focused exact 舊候選回刷接線**: `_fetch_retryable_candidate_skus()` 的 focused true-low / rescore 窄門新增 3W CLINIC 膠原蛋白粉底液 50ml x2、花美水 Moisture/Inclear 1.7g x3、KUSSEN 寶寶益菌屁屁膏 50ml 3 入、Lab52 齒妍堂嬰幼兒 / 汪汪隊牙刷 2 入。這些品線在 matcher 測試中已是 `exact / total_price / price_alert_exact`,本次只讓舊 `true_low_confidence` / `rescore_accepted_current` 候選能被新版 matcher 重新判斷;仍不放寬 `MIN_MATCH_SCORE`、hard veto、auto write safety 與 stronger existing match 保護。
- **V10.547 單位價覆核洞察與證據鏈保留**: `manual_unit_price_required` 現在會和 `unit_comparable` 一樣重新產生單位價比較,並轉成 `unit_price_insight`,明確標示 PChome 或 MOMO 哪邊單位價較低、差距百分比、嚴重度與操作建議Dashboard 覆核卡、商品列、決策信封與 OpenClaw/PPT 摘要都可讀到這個訊號。人工覆核寫回 `competitor_match_attempts` 時也會在欄位存在時保留原始 `match_diagnostic_json``comparison_mode``hard_veto``diagnostic_codes``competitor_match_reviews.candidate_diagnostic` 同步附帶 JSON 證據,避免人工閉環後只剩狀態文字。
- **V10.546 近門檻舊候選回刷隊列補漏**: `run_retryable_candidate_revalidation()` 的候選來源不再只看每個 SKU 最新一筆 attempt。新增 `legacy_unmasked_attempt`,當最新狀態是 `no_result` / `refresh_no_result` / `expired_match` 時,可回撈同 SKU 早期 `low_score``recoverable_low_score``true_low_confidence``rescore_accepted_current` 的近門檻候選,再交給最新版 matcher 重評。此入口仍要求 candidate product id、分數下限、無 hard veto、`exact_identity`且不打開人工否決、單位價、identity_veto 或 protected existing match避免為了覆蓋率破壞安全邊界。
- **V10.545 Dashboard 比價覆蓋率口徑收斂**: 商品看板與 PChome 覆核頁把「身份覆蓋率」與「可用比價覆蓋率」拆成明確欄位coverage cache 更新為 v9 並回傳 `identity_coverage_*``pending_identity_count``stale_identity_count``last_decision_ready_crawled_at`。覆核 KPI 改只計算真正待處理狀態,人工否決 / 人工單位價 / 需補研究另列 `manual_closed_count`避免人工閉環候選被混進待審總數。Dashboard 的 PChome competitor map 也改成只取新鮮、有效價格、identity_v2 的最新 row資料新鮮度改看可用比價 row不再被無效或低信心抓取紀錄撐高。
- **V10.544 變體安全與 YES 工具線收斂**: 延續近門檻 `low_score` 救回,但把安全邊界補得更硬。新增 YES 德悅氏指甲工具精準線,只有同品牌、同工具線、同尺寸且同亮面/霧面/可收納/三面等關鍵款式時才進 `total_price`,並接入 revalidation SQL。同步新增未知香味差異與無型號指彩色名差異 hard vetoMUJI / COCODOR 不同香型、OPI 無型號不同色名不再被高分誤配HOOOME 暖燈陶瓷/玻璃/水晶/金屬等材質差保留人工覆核。搜尋詞對護手霜、擴香瓶、無型號指彩優先帶上香味/色名,提升 crawler 找到真同款候選的機率。
- **V10.543 rescore accepted 窄門回刷與高信心線補強**: `run_retryable_candidate_revalidation()` 追加 `rescore_accepted_current` 窄門,只允許已進人工池且命中具名 focused exact 品線的候選重新評分,仍由 matcher 判定是否可寫正式價差。新增 SK-II 青春露 330ml 兩入、AMIINO 安美諾美白修護霜 30ml、YES 腳指甲剪刀 10.5cm、YES 極細指甲緣硬皮剪刀 9cm 的 total-price 安全線同時新增指甲油型號衝突防線ANNY `A10.074.60` vs `A10.500`、OPI 不同 `ISL...` 型號都會 hard veto不會為了拉覆蓋率誤配色號。
- **V10.542 可用比價覆蓋率口徑拆分**: `fetch_competitor_coverage()` 新增 `decision_ready_matches` / `decision_ready_rate`,以「高信心 identity 且價格仍新鮮」除以 ACTIVE 商品數,和 `match_rate`(身份覆蓋)及 `fresh_match_rate`已配對中的新鮮率分開。Dashboard 第一屏改顯示可用比價覆蓋率daily / growth / Webcrumbs / OpenClaw payload 同步輸出,避免使用者把舊截圖的低價格可用率、身份覆蓋率與新鮮率混成同一個 KPI。
- **V10.541 高信心覆核池 exact 線再收斂**: 從正式覆核頁抓到多筆 `rescore_accepted_current` 仍卡人工的同款The Ordinary 咖啡因 EGCGMOMO 單側漏 30ml、Natures Care 綿羊油同入數、TOMOON 指甲剪同 L/S 尺寸、HH 私密潔淨露+私密衣物手洗精雙 200ml、SEBAMED 護潔露 200ml x2、YES 德悅氏 9cm 剪刀。新增 focused total-price 規則與 revalidation SQLTOMOON / O.P.I 仍要求同型號或同尺寸,避免跨款式誤配。
- **V10.540 O.P.I 指彩精準型號救回**: 正式覆核頁面顯示多筆 O.P.I 類光繚 / 如膠似漆指彩因 score 0.76~0.83 停在 `rescore_accepted_current` 人工池,但雙方都有明確 `ISL...` 型號(如 ISLL87、ISLL00、ISLN25。新增 `opi_gel_polish_exact_model` focused total-price 規則:必須同品牌、同類光繚指彩線、共享型號 token不同型號/色號不自動通過。同步接入 revalidation SQL讓舊 `true_low_confidence` 指彩候選可批次重評。
- **V10.539 任選 catalog focused exact 與 commercial 防線**: 新增 FLORTTE 水果沙拉眼線液筆 0.5ml、露得清護手霜 56g 無香/有香、Kanebo ALLIE 持采亮化 UV 防曬水凝乳 60g 的 focused total-price 規則,條件是雙方同品牌、同品線、同規格且任選 catalog 語意一致;同步接入 `run_retryable_candidate_revalidation()`。同時修正 focused bypass若存在 `commercial_condition_gap`(例如即期品),不得移除 `variant_selection_review`,避免商業狀態差異被自動寫入正式價差。
- **V10.538 ai_calls provider CHECK 對齊**: 正式 scheduler Hermes/Ollama 全失敗時會以 `provider=ollama_other` 記錄未知/未選定 host`ai_calls.chk_ai_calls_provider` 舊白名單未包含此 telemetry bucket導致觀測寫入再撞 CHECK。新增 migration 043 放行 `ollama_other`,並讓 `ai_call_logger` 將空值、unknown、非白名單 provider 字串正規化為允許值;`ollama_other` 僅作遙測分類,不是模型路由目標。
- **V10.537 focused exact revalidation queue 接線**: V10.536 只補 matcher 規則會影響新抓取,但無法批次回收既有 `true_low_confidence` 舊候選。`run_retryable_candidate_revalidation()` 新增 focused true-low 窄門:花美水 Relax、St.Clare 私密呼呼、BIOPEUTIC 果酸、台塑生醫、Elizabeth Arden 與理膚寶水若無 hard veto 與型別/款式/香味/件數/組合阻擋,可進重評;`variant_selection_review` 僅在這些具名安全線允許重跑,其他人工池不打開。
- **V10.536 高分 true_low_confidence focused exact 救回**: production 抽樣顯示剩餘未覆蓋集中在 `identity_veto``true_low_confidence`,其中部分 1.0 分樣本是同品牌、同品線、同規格/同組合,但因多件組或護唇/私密護理類型辨識保守而停在 manual review。新增花美水 Relax、St.Clare 私密呼呼、BIOPEUTIC 果酸、台塑生醫嬰兒沐浴洗髮、Elizabeth Arden 八小時護唇膏、理膚寶水全面修復潤唇膏的 focused total-price 規則;不放寬 `MIN_MATCH_SCORE`,也不移除色號/香味/款式防線。
- **V10.535 ElephantAlpha price trigger 查詢瘦身**: 正式 scheduler 日誌顯示 `price_drop_alert` trigger 對整張 `price_records``DISTINCT ON` 最新價造成 statement timeout。`price_drop_alert``market_opportunity` 與 EA DB evidence prefetch 改為先篩最近有效 PChome identity_v2 競品,再用 `JOIN LATERAL` 只查該 SKU 最新 MOMO 價格,保留 match_score/tags/diagnostic evidence 給 Telegram HITL不再用全表最新價子查詢。
- **V10.534 rescore accepted gate 收緊與語意修正**: 正式 96 筆 `rescore_accepted_current` 盤點顯示多數仍是 `manual_review / identity_review`,且有 2 筆 `no_match / none / suppress` 混入。收緊 `classify_match_attempt_row()``no_match``price_basis=none``alert_tier=suppress` 不得 gate pass新增 `--retract-unsafe-accepted` 可把既有 unsafe accepted 退回 `true_low_confidence`。Dashboard / daily / growth / OpenClaw 文案改成「重算待人工覆核」,明確表示仍需人工確認身份後才可寫正式價差。
- **V10.533 ElephantAlpha legacy OpenClaw advisory 相容**: 正式 scheduler 日誌出現 `Unrecognized step: agent=openclaw action=generate_dynamic_pricing_strategy`,屬於舊協調器把建議型策略文字放進 execution plan。執行器現在將 `generate_dynamic_pricing_strategy` 納入既有 OpenClaw advisory no-op 清單,只記錄 skipped不觸發 circuit breaker也不轉成自動調價或外部呼叫。
- **V10.532 coverage / review queue 口徑對齊**: V10.531 materialize 96 筆 `rescore_accepted_current`DB 最新狀態正確,但 `/api/ai/pchome-match/backfill/status``rescore_accepted_count` 仍為 0。原因是 coverage 的 `attempt_status` 統計只看「完全沒有 identity」商品而 review queue 看的是「沒有新鮮有效 identity」商品。改為以 `fresh_competitor` 排除條件統計,讓 stale identity 的重算可採用待審能正確上屏;正式價差表仍未被 rescore materialize 寫入。
- **V10.531 PChome 安全 exact 規則補強**: production refresh 顯示大量舊 identity 不是分數不足,而是被多件組 / 護唇品 variant 防線過度保守地擋在 `identity_review`。新增 `safe_multi_component_exact_total_price`:同品線、同規格、同數量且商品型別完全對齊、無 variant / count / bundle / commercial / unit-price 阻擋時,才可進 `exact / total_price / price_alert_exact`;另補 DHC 純欖護唇膏 1.5g、FRUDIA 蜂蜜藍莓護唇膏 10g、SEBAMED 嬰兒護唇膏 4.8g x2、理膚寶水滋養修護潤唇膏 4.7ml focused total-price。回歸測試保留 HH 混合組、TS6 香味衣物手洗精、粉底色號與蠟燭 catalog 不自動放行。
- **V10.530 retryable preview 輕量化與 recover-stale 安全閘**: 正式站 profiling 證實 `/api/ai/pchome-match/backfill/status` 剩餘瓶頸在 `revalidation_preview`,約 12 秒;`_fetch_retryable_candidate_skus()` 改為先取每個 SKU 最新 attempt 並縮小到可重評候選,再 `JOIN LATERAL` 取單一最新 MOMO 價,不再對全量 `price_records` 做商品 window scan。正式 smoke 也顯示過期 identity fresh-search rescue 小批次 5 筆耗時約 109 秒且 0 筆成功,因此 Dashboard 移除「救援過期 40 筆」按鈕,只保留 `stale_recovery_preview` 只讀觀測;後端 `/api/ai/pchome-match/recover-stale` 保留但需明確設定 `PCHOME_STALE_RECOVERY_ENABLED=true` 才能執行,避免低成功率慢任務拖住正式 worker。
- **V10.529 recover-stale 名稱風險擋詞補強**: 過期 identity 搜尋救援新增 `+``x2``*2` 等組合暗示,以及湛藍、麋香、海洋、玫瑰、薰衣草、生理呵護、日用型、清爽、潤澤等常見變體 / 香味 / 版本詞;避免同品牌同規格但不同香味、不同膚感或不同使用情境的 stale pair 進慢速 fresh search。
- **V10.528 recover-stale preview 輕量化**: V10.527 的救援隊列在正式站 preview 時曾造成 status API 超時。改為雙階段篩選SQL 從過期 `competitor_prices` 小集合出發,只做 identity_v2、過期、exact/total_price/price_alert_exact 等必要條件並限制候選量,再用 `JOIN LATERAL` 取 ACTIVE 商品最新 MOMO 價variant / catalog / commercial condition / 高風險名稱訊號改在 Python 對小樣本過濾,避免 `/api/ai/pchome-match/backfill/status` 因全量 price_records、JSONB + regex preview 查詢拖垮。
- **V10.527 PChome 過期 identity 搜尋救援隊列收斂**: V10.526 production smoke 發現直接對全部過期 `identity_v2` 做 rescue 會把香氛 / 色號 / 目錄款 / 商業狀態差異等人工覆核型 stale pair 送進慢速 fresh search20 筆耗時 361 秒且 0 筆成功。新增 `_fetch_expired_identity_recovery_skus()` 作為救援專用隊列,只收既有正式診斷為 `exact_identity / total_price / price_alert_exact` 且無 variant、catalog、commercial condition、count、bundle、unit-price 等阻擋理由的舊配對;名稱含任選、多款、香味、色號、即期、融燭燈、香氛蠟燭等高風險訊號先排除。
- **V10.526 PChome 重評預覽與過期 identity 搜尋救援**: `/api/ai/pchome-match/backfill/status` 新增 60 秒快取的 `revalidation_preview``stale_recovery_preview`Dashboard 補抓產線顯示「可重評 / 窄門 / 可救援」數字;兩個 preview 都只讀 DB不啟動 PChome 搜尋、不呼叫 LLM、不寫 `competitor_match_attempts` 或正式價格表。另新增 `/api/ai/pchome-match/recover-stale` 與「救援過期 40 筆」按鈕,對過期 `identity_v2` 先查既有 product_id只有在舊 ID 缺失或低分時才走受控 fresh-search recovery最後仍經 hard veto、auto price write safety 與 overwrite protection 才能寫入正式比價。
- **V10.525 高分 review-gated exact 舊候選窄門重評**: `run_retryable_candidate_revalidation()` 保持主戰場為 `low_score / refresh_low_score / recoverable_low_score`,只額外收 Beauty Foot、KAMERIA、TS6、Vaseline 這批已由 V10.523 補 focused exact 規則的 `true_low_confidence` 舊候選。入口要求舊分數 >= 0.95、仍為 `exact_identity`、具備 `strong_exact_spec_match`,且不得含 `commercial_condition_gap`、variant、count、bundle、refill 等阻擋理由;讓已驗證真同款可被回刷,不把整個人工審核池自動打開。
- **V10.524 PChome 過期價格刷新手動入口**: 商品看板 PChome 補抓產線新增「刷新過期 120 筆」按鈕與 `/api/ai/pchome-match/refresh-stale`,背景執行既有 `run_expired_identity_refresh()`,只刷新已建立 `identity_v2` 的 PChome product_id不跑 fresh search recovery、不呼叫 LLM完成後重算 AI 挑品並清除 Dashboard / competitor intel cache`stale_matches` 從觀測指標變成可直接操作的任務。
- **V10.523 高分真同款 exact identity 比價規則補強**: 針對正式環境反覆出現、分數已達 1.0 但因 `multi_component_pair` 或 variant review gate 被留在人工審核的真同款,補 Beauty Foot 足膜、KAMERIA 積雪草足膜、TS6 蜜愛潤滑液 / 蜜桃煥白凝膠 / 極淨白+煥白組合、Vaseline 嬰兒高純修護凝膠 focused exact identity。這些案例只有在品牌、品線、容量 / 重量與入數完全對齊時才進 `exact / total_price / price_alert_exact`TS6 香味衣物手洗精等款式敏感商品仍維持 `manual_review`,全域 `MIN_MATCH_SCORE` 與 overwrite 保護不變。
- **V10.522 PChome backfill status 附帶 coverage snapshot**: `/api/ai/pchome-match/backfill/status` 在背景任務狀態外同步回傳 read-only `fetch_competitor_coverage()` 摘要包含身份覆蓋、新鮮率、過期價格與待補抓數Dashboard 補抓產線即使尚無最近 run result也會顯示「身份覆蓋 / 新鮮 / 待刷新 / 待補抓」,讓操作員能分辨下一步該跑 expired identity refresh 還是 unmatched backfill。此狀態端點不寫 DB、不呼叫 LLM、不抓外站。
### 2026-05-31Webcrumbs 共用 UI Runtime 與市場情報 writer approval
- **V10.521 比價新鮮度 stale 指標上屏**: 首頁比價監控總覽、PChome 補抓產線、daily 競價覆蓋與 growth 比價資料品質同步顯示 `stale_matches` / 價格過期數,讓操作員能分清「已確認同款但價格待刷新」與「尚未找到身份配對」,不再只看到新鮮率下降。過期 identity refresh 也優先刷新 `total_price / price_alert_exact` 的正式價差配對,讓最能進決策與告警的舊價格先回新鮮。
- **V10.520 PChome 過期價格刷新快慢路徑拆分**: `run_expired_identity_refresh()` 改為只刷新已確認 `identity_v2` 的既有 PChome product_id若 product_id 已查不到或回傳後低分,不再同步跑慢速 fresh search recovery而是記錄 `refresh_no_result` / low-score 並交給 `run_retryable_candidate_revalidation()` 的近門檻救援路徑。這能避免正式回刷 500+ 筆時被少數缺失 ID 拖到長時間卡住,讓價格新鮮度批次回升更可控。
- **V10.519 Webcrumbs host data metadata 對齊新覆蓋率口徑**: Webcrumbs host data metadata 同步輸出 `fresh_match_count``fresh_match_rate``stale_match_count``pending_match_count`,讓共用 UI / 其他專案 proxy 能分清身份覆蓋與價格新鮮度,不再只看到舊的 matched_count / coverage_rate。
- **V10.518 PChome 覆蓋率與新鮮度拆分**: 修正比價監控總覽把價格 TTL 過期誤算成「未覆蓋」的產品口徑,`fetch_competitor_coverage()` 現在分開回報 `valid_matches`identity 覆蓋)、`fresh_matches`(價格新鮮)、`stale_matches``fresh_match_rate`首頁、業績與成長頁同步顯示身份覆蓋與價格新鮮。PChome 快取 TTL 預設由 6h 改 48h並將每日 expired identity refresh / retryable / unmatched limits 改為環境變數,預設提升到 1200 / 240 / 240避免已建立 identity 的商品因刷新量不足被長期視為無覆蓋。
- **V10.517 PChome near-threshold 比對 hotfix**: 新增 Lab52 齒妍堂汪汪隊嬰幼兒牙刷 2 入組 focused exact identity讓真同款可進 `exact / total_price / price_alert_exact`;同時補 Les nez 香氛融蠟燈款式選擇 gap 與 Time Leisure 香薰蠟燭香味 gap將不同款式 / 單側香味候選留在覆核或 veto不讓它們進 recoverable 自動回刷。測試鎖住 Dashing Diva、Pavaruni、Recipe Box、Lactacyd 與 feeder recoverable 邊界。
- **V10.516 Webcrumbs host data 授權回歸測試**: 新增 Flask runtime 測試,直接重現 `DISABLE_LOGIN=true``/api/webcrumbs/marketplace-host-data` 必須回 401 且不得組裝真實 host data同時鎖住 `X-Internal-Key` 與登入 session 可取得敏感 seed、未授權 `/webcrumbs` 只注入 `auth_required` 空狀態,避免後續改動再讓 public 診斷頁洩漏 MOMO/PChome SKU 與價差。
- **V10.515 Webcrumbs host data 硬性授權**: 發現正式環境一般 `@login_required` 可能因 `DISABLE_LOGIN=true` 放行後,為 `/api/webcrumbs/marketplace-host-data``/webcrumbs` inline seed 加上獨立授權判斷;只有登入 session 或 `X-Internal-Key` 可取得真實 SKU/價差,未授權時只回 `auth_required` 空狀態,避免 public runtime 診斷頁洩漏正式比價資料。
- **V10.514 Webcrumbs host data read-only API**: 新增登入後 `/api/webcrumbs/marketplace-host-data`,回傳與 `/webcrumbs` inline seed 相同的 MOMO/PChome exact 價差 host data contract供 plugin、QA 與其他專案 proxy 驗證API boundary 明確標示 `writes_database=false``calls_llm=false``fetches_external=false`,且只允許 exact / total_price / price_alert_exact 摘要。
- **V10.513 外部工具診斷 payload 模組化**: 新增 `services/external_tool_payload_service.py`,把 Metabase/Grist/Webcrumbs 診斷頁 payload 與 Webcrumbs host data 組裝從 `routes/system_public_routes.py` 移出route 保持 HTTP glue 與 asset proxy避免 Webcrumbs live plugin 與比價 host data 持續把公開系統 route 撐成大檔。
- **V10.512 Webcrumbs MOMO/PChome host data**: 新增 `services/webcrumbs_host_data_service.py`,讓 `/webcrumbs` live plugin preview 復用 `competitor_intel_repository.fetch_top_competitor_risks()` 與 coverage將 exact / total_price / price_alert_exact 的只讀價差摘要轉成 `StockPlatformSharedUI.marketSnapshot` / `aiCandidate`;不呼叫 LLM、不抓外站、不寫 DB無風險或讀取失敗時仍輸出安全空狀態。
- **V10.511 Webcrumbs host data 安全空狀態**: `/webcrumbs` 會注入 `StockPlatformSharedUI.marketSnapshot` / `aiCandidate` 的診斷空資料,避免 Shared UI Hub plugin 因資料源未接入而 fallback 顯示假市場數字、假 AI 候選或假信心分數。
- **V10.510 Webcrumbs live plugin 試點**: `/webcrumbs` 診斷頁不再只顯示 runtime 設定,新增 `StockPlatformSharedUI.allowedPluginUris` 與同源 `/webcrumbs-assets/plugins/finance.market-ticker-strip/0.1.0``finance.ai-candidate-card/0.1.0` live plugin embed讓 shared-ui loader、plugin asset proxy 與頁面初始化時序能在 momo-pro 內直接驗收。
- **V10.509 市場情報 MCP Fetch Candidate Queue Writer Review Decision Approval Writer Preflight gate**: 新增 `/api/market_intel/mcp_fetch_candidate_queue_writer_review_decision_approval_writer_preflight` 與 UI preview只審核 human approval 通過後的 operator writer preflight 摘要;要求 approval linkage、writer_preflight_id、target operation、row count、dedupe keys、approved decision 到 target review_state 的逐列映射、decision/approval/preflight evidence refs、artifact paths、matched row exact-identity/variant/overwrite guard 與 operator confirmation 對齊,且 API 不讀 token、不執行 CLI、不開 DB、不寫 preflight/approval/decision/match、不更新 review_state、不補 queue、不掛 scheduler只放行到後續 CLI review / run package 設計。
- **V10.508 Webcrumbs 同源 asset proxy 收斂**: 正式頁面 runtime 預設改走 `/webcrumbs-assets/loader/webcrumbs-compatible-loader.js`,由 momo-pro 代理 188 Shared UI Hub 的 allowlist asset path`loader/``plugins/``demo/`),避免 `webcrumbs.wooo.work` 公網 TLS、Basic Auth 或入口轉發尚未完成時造成頁面 script 載入失敗;`/webcrumbs` 診斷頁同步顯示 asset upstream`WEBCRUMBS_PLUGIN_BASE_URL` 預設改為同源 `/webcrumbs-assets/plugins`
- **V10.507 Webcrumbs 共用 UI Runtime 接入**: 新增 `WEBCRUMBS_*` 設定、`/webcrumbs` 診斷頁、全站 `ewoooc_base.html` runtime script 載入守門與側欄入口runtime 僅允許自架固定版本 URL禁止正式環境使用官方 `@latest`,並新增 `docs/guides/webcrumbs_shared_runtime.md` 與 ADR-037 記錄共用 microfrontend/plugin loader 邊界。
- **V10.506 市場情報 MCP Fetch Candidate Queue Writer Review Decision Approval gate**: 新增 `/api/market_intel/mcp_fetch_candidate_queue_writer_review_decision_approval` 與 UI preview只審核 review decision 通過後的 operator human approval 摘要;要求 decision linkage、approval identity、target table、row count、dedupe keys、`approved_for_writer_preflight` approval result、decision/approval evidence refs、artifact paths、matched row exact-identity/variant/overwrite guard 與 operator confirmation 對齊,且 API 不讀 token、不執行 CLI、不開 DB、不寫 approval record、不寫 decision record、不更新 review_state、不寫 match result、不補 queue、不掛 scheduler只放行到後續 writer preflight 設計。新 endpoint 拆到 `routes/market_intel_mcp_review_routes.py`,避免既有 MCP run route 繼續膨脹。
### 2026-05-24PChome 近門檻身份回收第二輪
- **V10.505 市場情報 MCP Fetch Candidate Queue Writer Review Decision gate**: 新增 `/api/market_intel/mcp_fetch_candidate_queue_writer_review_decision` 與 UI preview只審核 review inventory 通過後的 operator candidate queue review decision 摘要;要求 decision identity、target table、row count、dedupe keys、`needs_review` 現態、允許決策集合、evidence refs、matched row exact-identity/variant/overwrite guard 與 operator confirmation 對齊,且 API 不讀 token、不執行 CLI、不開 DB、不寫 decision record、不更新 review_state、不寫 match result、不補 queue、不掛 scheduler只放行到 decision approval / writer preflight 設計。
- **V10.504 市場情報 MCP Fetch Candidate Queue Writer Review Inventory gate**: 新增 `/api/market_intel/mcp_fetch_candidate_queue_writer_review_inventory` 與 UI preview只審核 writer review handoff 通過後的 operator read-only candidate queue inventory 摘要;要求 handoff identity、target table、row count、dedupe keys、review_state、artifact paths、read-only query result、missing/duplicate rows 與 operator confirmation 對齊,且 API 不讀 token、不執行 CLI、不開 DB、不寫 queue、不更新 review_state、不做 inventory query、不掛 scheduler只放行到後續人工 candidate queue review。
- **V10.503 市場情報 MCP Fetch Candidate Queue Writer Review Handoff gate**: 新增 `/api/market_intel/mcp_fetch_candidate_queue_writer_review_handoff` 與 UI preview只審核 post-closeout inventory review 通過後的 operator candidate queue review handoff 摘要;要求 inventory linkage、handoff identity、target table、row count、artifact paths、review contract、forbidden API actions 與 operator confirmation 對齊,且 API 不讀 token、不執行 CLI、不開 DB、不寫 queue、不更新 review_state、不掛 scheduler只放行到人工 candidate queue review。
- **V10.502 AiderHeal 自動修復診斷鏈修正**: `execute_code_fix()` 改為先檢查 ADR-020 檔案白名單再執行 110 preflight避免 `tests/...` 這類不得自動修的 finding 被誤報成 `/home/wooo/ewoooc` preflight 失敗Code Review 完成通知會把全數不在白名單的 finding 標成需人工處理,不再宣稱已觸發 AiderHeal白名單同步放行 `services/routes/database` 子目錄 Python 檔preflight 通知帶 stderr/stdout 細節,健康檢查接受正式 `/health` 回傳的 `healthy`
- **V10.501 市場情報 MCP Fetch Candidate Queue Writer Post-Closeout Inventory Review gate**: 新增 `/api/market_intel/mcp_fetch_candidate_queue_writer_post_closeout_inventory_review` 與 UI preview只審核 closeout review 通過後的 operator live inventory read-only 摘要;要求 closeout linkage、row count、inventory artifact、closeout review artifact、read-only query result、missing/duplicate rows 與 operator confirmation 對齊,且 API 不讀 token、不執行 CLI、不開 DB、不寫 queue、不做 inventory query、不掛 scheduler只放行到 candidate queue review handoff。
- **V10.500 市場情報 MCP Fetch Candidate Queue Writer Run Closeout Review gate**: 新增 `/api/market_intel/mcp_fetch_candidate_queue_writer_run_closeout_review` 與 UI preview只審核 receipt review 通過後的 operator closeout 摘要;要求 receipt linkage、closeout artifact、receipt review artifact、post-closeout inventory plan、writer output / post-write smoke / backup manifest、rollback note 與 operator confirmation 對齊,且 API 不讀 receipt 原文、不讀 token、不執行 CLI、不開 DB、不寫 queue、不做 post-closeout query、不掛 scheduler只放行到 read-only post-closeout inventory review。
- **V10.499 市場情報 MCP Fetch Candidate Queue Writer Run Receipt Review gate**: 新增 `/api/market_intel/mcp_fetch_candidate_queue_writer_run_receipt_review` 與 UI preview只審核操作員 shell writer run 後貼回的 receipt 摘要;要求 readiness linkage、run package id、候選/dedupe keys、writer output、post-write smoke、backup path 與 operator confirmation 對齊,且 API 不讀 receipt 原文、不讀 token、不執行 CLI、不開 DB、不寫 queue、不做 post-write query、不掛 scheduler只放行到 closeout review。
- **V10.498 市場情報 MCP Fetch Candidate Queue Writer Run Readiness gate**: 新增 `/api/market_intel/mcp_fetch_candidate_queue_writer_run_readiness` 與 UI preview只審核 run package review 後的 operator readiness 證據;要求 run readiness artifact、reviewed sample、備份、read-only preflight 與 post-write smoke 路徑安全,並確認 CLI-only、approval token shell-only、無 API/DB/file/scheduler 副作用。API 不產檔、不讀 token、不執行 CLI、不開 DB、不寫 queue、不掛 scheduler只放行到後續 run receipt review。
- **V10.497 市場情報 MCP Fetch Candidate Queue Writer Run Package Review gate**: 新增 `/api/market_intel/mcp_fetch_candidate_queue_writer_run_package_review` 與 UI preview只審核 CLI review 後的 operator run package 草案;要求 package identity、artifact manifest、operator shell command sequence、candidate/dedupe keys 與 CLI review 完全對齊,且 API 不產檔、不讀 approval token、不執行 CLI、不開 DB、不寫 queue、不掛 scheduler只放行到 run readiness review。
- **V10.496 市場情報 MCP Fetch Candidate Queue Writer CLI Review gate**: 新增 `/api/market_intel/mcp_fetch_candidate_queue_writer_cli_review` 與 UI preview只審核 writer preflight 後的 CLI review 草案;要求 script path、target table、preflight id、payload row count、candidate/dedupe keys 與 command argv 完全對齊,並禁止 `--execute``--apply-real-write``--approval-token` 進 API payload且 API 不執行 CLI、不讀 token、不寫檔、不開 DB、不寫 queue、不掛 scheduler。
- **V10.495 市場情報 MCP Fetch Candidate Queue Writer Preflight gate**: 新增 `/api/market_intel/mcp_fetch_candidate_queue_writer_preflight` 與 UI preview只審核 queue review 後的 writer preflight 草案;要求 `target_table=market_alert_review_queue``write_mode=cli_only_later`、dedupe strategy、insert columns、payload rows 與候選 key 完全對齊,且 API 不開 DB、不執行 CLI、不建立 queue、不更新 review_state、不寫 DB、不連外、不掛 scheduler。
- **V10.494 市場情報 MCP Fetch Candidate Queue Review gate**: 新增 `/api/market_intel/mcp_fetch_candidate_queue_review` 與 UI preview只審核 candidate handoff 後的人工 queue review 草案;要求候選 key 完全對齊、`review_state=needs_review`、allowed actions 限人工確認/否決/延後、`queue_write_status=not_persisted`,且 API 不建立 queue、不更新 review_state、不寫 DB、不連外、不掛 scheduler。
- **V10.493 市場情報 MCP Fetch Candidate Handoff Review gate**: 新增 `/api/market_intel/mcp_fetch_candidate_handoff_review` 與 UI preview只審核 parser review 後的候選交接包;要求 source/candidate key 完全對齊、queue policy 維持 `manual_candidate_review` / `preview_only`、候選數維持小批次,且 API 不建立 queue、不寫 DB、不讀 artifact、不連外、不掛 scheduler。
- **V10.491 市場情報 MCP Fetch Result Parser Review gate**: 新增 `/api/market_intel/mcp_fetch_result_parser_review` 與 UI preview只審核操作員 shell parser 後貼回的結構化摘要API 不讀 artifact、不執行 parser CLI、不抓外站、不寫檔、不開 DB、不掛 scheduler且會阻擋 raw HTML/body/snapshot、secret/token 欄位與 side-effect flags。
- **V10.489 PChome 低分同款人工覆核回收與 gate-pass 風險邊界**: `marketplace_product_matcher` 新增三個窄範圍 focused identityTS6 超美白香氛誘霜 120g/ml、W 修護保養蝸牛特潤修護面膜 6 片、Derma 大地 Eco 植萃護膚油 2 入。這些樣本只升到 `identity_review / manual_review`,不進 `price_alert_exact`;同版補 Clarins 身體油不同線、命名組合品數量反轉、isLeaf 香型數量不一致 hard vetoHOOOME 大理石暖燈單側設計差留人工覆核。
- **V10.488 市場情報 MCP Fetch Run Receipt gate**: 新增 `/api/market_intel/mcp_fetch_run_receipt` 與 UI preview只審核操作員 shell dry-run 後貼回的 receiptAPI 不執行 CLI、不抓外站、不寫檔、不開 DB、不掛 scheduler且會阻擋 secret/token 欄位與 side-effect flags。
- **V10.473 背景 embedding 讀取 host_health skip**: `OllamaService.generate_embedding(..., allow_111_fallback=False)` 會先查最近 `host_health_probes`;若 GCP-A/GCP-B 在 20 分鐘視窗內已由 runtime probe 標成 unhealthy背景 embedding 直接跳過該節點並開短暫 GCP circuit不等待 30 秒 timeout、不落 111。DB 讀取失敗時 fail-open 回原本 retry避免觀測層阻斷 embedding。
- **V10.472 GCP Ollama failover rootless 診斷**: 新增 `scripts/ops/diagnose_ollama_gcp_failover.sh` 與 DevOps SOP可不需 root 檢查 GCP-A/GCP-B/111 direct、110 proxy `11435/11436` 與 GCP-B `bge-m3` runtime。現況確認GCP-A `22/11434` refused、GCP-B `22/11434` open 但 SSH key denied、GCP-B embed OK、110:11435 502、110:11436 OKprimary 修復需 GCP/SSH 或 110 root 權限。
- **V10.471 GCP-B embedding timeout 校準**: GCP-B `bge-m3` `/api/embed` 直接實測約 6.4s / 7.3s / 23.5s,原 `OLLAMA_EMBED_MAX_TIMEOUT=15` 與 host health `OLLAMA_HOST_HEALTH_EMBED_TIMEOUT=8` 會誤判慢但成功的 embedding預設改為 30s。背景 embedding 仍只跑 GCP-A/GCP-B不落 111。
- **V10.470 Ollama host health 實作探針**: `run_host_health_probe()` 對 GCP-A / GCP-B 在 `/api/tags` 成功後追加短 `bge-m3` `/api/embed` probe避免 GCP-B 出現 tags/version 正常、但實際 embedding runner 20s timeout 時仍被標 healthy111 預設不做背景 embedding probe避免監測任務把 fallback Mac 載入 `bge-m3`
- **V10.469 Background embedding 降級語意修正**: `OllamaService.generate_embedding(..., allow_111_fallback=False)` 在 GCP-A/GCP-B 全失敗時會開啟短暫 failure circuit 並記 WARNING不再把背景 `bge-m3` 降級熔斷每分鐘寫成 ERROR同步或允許三主機 fallback 的 embedding 全失敗仍維持 ERROR保留真正阻塞型故障訊號。
- **V10.468 Ollama import-time / embedding 熔斷治理**: `config.OLLAMA_HOST``HERMES_URL``EMBEDDING_HOST` 舊相容常數改成靜態核准 env reader不再於 import 時呼叫 `resolve_ollama_host()`,避免 GCP-A/GCP-B 短暫拒連時把 process 常數 freeze 到 111。`generate_embedding(..., allow_111_fallback=False)` 在 GCP-A/GCP-B 都失敗後會開短暫 GCP embedding circuit避免背景任務每筆重打兩台故障主機111 仍不承接背景 `bge-m3`。維運盤點曾見 110 proxy 11435/11436 因 GCP 11434 refused 回 502部署 smoke 時 GCP-B `/api/version` 已恢復 200 並成為動態路由落點GCP-A 22/11434 仍 refused後續需以 GCP 權限恢復 primary Ollama 主機或 SSH key。
- **V10.467 Focused exact total-price 安全通道**: `marketplace_product_matcher` 新增窄範圍 `focused_exact_total_price_safe` lane僅針對正式近門檻樣本中同品牌、同品名、同規格/同入數的 3W CLINIC 粉底液 2入、花美水凝膠 3支、The Ordinary 咖啡因 EGCG 30ml、KUSSEN 屁屁膏 3入、Bone 擴香禮盒、1990 融燭燈白色款與 CANMAKE 淚袋盤,讓 `exact/manual_review` 可升到 `exact/total_price/price_alert_exact`;未放寬 `MIN_MATCH_SCORE`DASHING DIVA、唇彩、香味、色號/款式敏感商品仍維持 variant / veto 保護。Production pilot 已將 SKU `6101639``10074951``7760902``TP00074980000005``14774766``10142589``10262470``10262471``11308520` materialize 到人工覆核隊列,`true_low_confidence` 802→793、`rescore_accepted_current` 38→47`6101784` 即期品因商業條件不同仍留在低信心覆核。
- **V10.466 Rescore latest-state duplicate 修正與 7 SKU pilot**: `materialize_rescore_accept_reviews()` 的 duplicate 判斷改看最新 attempt而不是歷史任一 accepted若後續 crawler 又把同 SKU/候選覆蓋成 `true_low_confidence`,可重新追加 `rescore_accepted_current` 讓 Dashboard latest-state 正確進人工覆核。Production pilot 已將 SKU `14756069``11159042``13842560``8394210``15192547``10509765``10603780` materialize 到人工覆核隊列;`competitor_prices` 目標計數維持 7、`competitor_price_history` 目標計數維持 210未寫正式價差表。
- **V10.465 Embedding GCP fallback 修正**: `OllamaService.generate_embedding(..., allow_111_fallback=False)` 若 resolver 因 unhealthy cache 回 111會強制改試尚未嘗試的 GCP-A/GCP-B不再直接 `break` 造成 `tried=[]` 或只試單台 GCP-B背景 embedding 仍不允許落 111。
- **V10.464 Rescore SKU pilot 篩選**: `audit_competitor_match_attempt_rescore.py``fetch_match_attempt_rescore_rows()` 增加 `--sku` / `skus` 篩選,可針對 DR.WU 這類明確 cohort 做 3-10 筆精準 materialize不必為了 pilot 掃整批 `true_low_confidence`
- **V10.463 DR.WU / 達爾膚品牌 alias**: `marketplace_product_matcher``DR.WU / DR WU / DRWU / 達爾膚` 正規化,讓正式樣本中同規格玻尿酸保濕精華乳、杏仁酸亮白煥膚精華不再因品牌 token 不同被降成 brandless identity review測試鎖住 exact / total_price / price_alert_exact。
- **V10.462 PChome 補抓 UI 語意收斂**: Dashboard 補抓區塊標題、AI 中樞按鈕、前端 confirm 與 API 回覆全數改用「PChome 補抓產線 / 補抓未搜尋 / 未搜尋補抓」,避免「待比對」殘留在操作入口,和低信心待人工覆核混淆。
- **V10.461 Dashboard 未搜尋語意修正**: 商品看板未進入 PChome 搜尋/補抓的品項不再顯示籠統「待比對」,改成「尚未搜尋」與「尚未進入 PChome 補抓」,避免操作員誤以為已有候選但尚未人工覆核;前端守門測試鎖住不得回退成舊文案。
- **V10.460 ElephantAlpha 告警決策信封**: `resource_optimization` 會為資源壓力告警產生 deterministic `decision_envelope`,證據只來自 `action_plans`、CPU 實測與 hygiene 結果Telegram 同時顯示決策信封、量測指標、判讀、系統處置與下一步;`ea_escalation` 模板也會渲染信封並使用 `decision_id` 作為 `momo:eig:*` callback避免低信心升級告警只剩空泛文字或不可追蹤按鈕。
- **V10.459 protected_existing_match 決策封包**: PChome 覆核信封開始解析 `existing_match_conflict`,把既有正式候選、新候選、雙方 matcher score 與 score delta 寫入 evidence / expected_impact / guardrails新候選即使分數較高也維持 `can_auto_execute=false`,但 OpenClaw、PPT、Dashboard 與人工覆核可清楚看見該比較哪兩個候選。
- **V10.458 OpenClaw / PPT 決策信封摘要**: 新增 `summarize_review_decision_envelopes()` 作為 PChome 覆核信封共用摘要 formatterOpenClaw 週報/日報/月報、OpenClaw Bot competitor PPT data_summary 與 PPT KPI slide 都使用同一份 HITL / 資料品質 / action / trace 摘要,不再各自手寫 attempt_status 翻譯。
- **V10.457 Dashboard / Excel 決策信封連動**: 商品看板 PChome 覆核卡顯示 `decision_envelope` 的決策等級、資料品質、HITL 與 trace`/api/export/excel/pchome-review` 匯出新增決策信封 ID、建議代碼、責任人、資料品質、自動執行允許、阻擋原因與證據摘要讓下載檔仍保留不可自動寫正式價差的 guardrails。
- **V10.456 review queue 決策信封**: `fetch_competitor_review_queue()``fetch_competitor_review_queue_page()``/api/pchome-review/queue` 每筆 PChome 覆核候選都輸出 `decision_envelope`,包含標的 SKU/PChome 候選、match evidence、建議人工動作、預期價差、資料品質與「不可自動寫正式價差」guardrailsreview queue cache key 升到 v3避免正式環境沿用舊 payload。
- **V10.455 EventRouter 決策信封直送**: 已帶 `decision_envelope` 的價格/覆核事件會略過 L1/L2 AI 重新摘要,直接用 Telegram 證據模板通知;決策信封新增標的區塊,顯示 SKU、商品名稱、PChome 候選 ID/名稱,避免 NemoTron 已有實證的價格告警被二次生成文字稀釋或產生額外模型呼叫。
- **V10.455 rescore variant retraction CLI**: `audit_competitor_match_attempt_rescore.py --retract-variant-accepted` 可找出最新仍為 `rescore_accepted_current` 且帶 `variant_selection_review` 的 SKU追加 `true_low_confidence` 退回列;保留歷史 audit trail不刪資料、不寫正式價格表。
- **V10.454 production rescore 入人工覆核隊列**: 以 latest-sku-only 口徑重算 745 筆 `true_low_confidence`,先追加 2 筆人工覆核列V10.454 gate 補上 `variant_selection_review` 排除後SKU `8884618` KATE 怪獸級持色唇膏MOMO 多款任選 vs PChome 單一水光款)已退回最新 `true_low_confidence`,最終只保留 SKU `10922465` Herbacin 小甘菊護手霜 20ml 為 `rescore_accepted_current`。這次只寫 `competitor_match_attempts` 人工覆核列,未寫 `competitor_prices` / `competitor_price_history`,並已清除 Dashboard 與 competitor intel cache。
- **V10.454 feeder / rescore 正式寫入閘門**: `CompetitorPriceFeeder` 現在只允許 `exact + total_price + price_alert_exact` 的 matcher 結果自動寫入 `competitor_prices``manual_review``identity_review``variant_selection_review`(例如 MOMO 多款任選唇膏對 PChome 單一水光款)會保留在 `true_low_confidence` 覆核不得因分數剛過門檻而污染正式比價資料。Rescore audit 也會把 `variant_selection_review` 擋在 `accepted_current` 之外。
- **V10.453 matcher 安全回收規則**: 新增 Herbacin 小甘菊護手霜 20ml brandless 同款 anchor修正 `EX8` 型號不再被誤解析為 `x8` 入數;新增香氛固體凝膠 / 空氣芳香劑一側泛稱、一側明確香味或 No. 款式的 `aroma_scent_variant_conflict` veto。這輪目標是讓 retryable replay 可救回真同款,同時先封住 MIRAE 入數與 GONESH 香味款式的假陽性。
- **V10.452 PChome rescore audit 最新狀態口徑**: `scripts/audit_competitor_match_attempt_rescore.py``fetch_match_attempt_rescore_rows()` 預設改成先取每個 SKU 最新 attempt再套用 status / reason 篩選,與 Dashboard review queue 一致;需要回看歷史候選時才使用 `--include-historical-candidates`,避免舊低信心紀錄讓已修正、已否決或已入隊 SKU 重複回到操作報表。
- **V10.451 low_score 操作分流拆分與 queue API**: Dashboard 比價覆核頁不再只給一個籠統低信心分頁;新增「近門檻可救」「證據不足」「低信心舊候選」三個篩選,`competitor_intel_repository.REVIEW_STATUS_FILTER_GROUPS` 同步提供對應分流,`/api/pchome-review/queue` 也能用同一套 `review_status` 做 read-only smoke / operator tools 查詢,讓 matcher 回刷、人工覆核、OpenClaw 報表能分清楚可自動回收、應保守等待、與需補搜尋的候選。
- **V10.450 PChome 覆核 fast-count UI 語意與重算可採用指標**: 預設全量覆核頁跳過 exact count 時,模板會以「約」標記快取總數,避免操作員把快取總數誤認為即時計算;搜尋、分類與單一狀態分流仍保留精準總數。`fetch_competitor_coverage()` 同步輸出 `rescore_accepted_count`Dashboard、daily/growth 與 OpenClaw 摘要會把「重算可採用待審」獨立顯示,不再只混在一般覆核隊列。
- **V10.449 PChome 覆核 exact count 條件修正**: 只有預設「全部覆核、無搜尋、無分類」頁跳過 exact count若使用搜尋詞、分類篩選或單一 review status仍保留精準總數避免操作員分頁資訊失準。
- **V10.448 PChome 覆核全量頁跳過 exact count**: `review_status=all` 改用 shared overview cache 的待處理總數作為分頁總數提示,當頁只查 50 筆;單一狀態分流仍保留 exact count避免每次操作全量覆核頁都為總筆數重掃整個 review queue。
- **V10.447 PChome 覆核頁查詢方向反轉**: review queue page 改由最新 `competitor_match_attempts` 的可覆核狀態先縮小候選,再 join ACTIVE 商品與最新價,並用 `NOT EXISTS` 排除已有有效 `identity_v2` 正式 PChome 價格;避免「全部覆核」每次先掃全站 ACTIVE 商品後才過濾,提高核心比價覆核頁可操作性。
- **V10.446 PChome 覆核頁 overview timeout 修正**: 覆核頁輕量 render path 的總覽改讀既有 shared dashboard cache / stale cache若快取不存在只用目前覆核頁資料補足 review count 與狀態分流,不再即時呼叫 `_load_competitor_decision_overview(session)` 的重型 SQL避免正式資料量下 statement timeout。
- **V10.445 PChome 覆核頁輕量渲染路徑**: `filter=pchome_review` 直接走覆核隊列專用 render path不再先建完整 Dashboard `unique_items`;當頁只查 50 筆覆核 SKU 的商品資料、最新價、昨日價與週前價仍沿用同一張新版表格、狀態分流、PChome 候選說明與人工覆核按鈕,降低核心比價覆核頁的全站資料負載。
- **V10.444 PChome 覆核頁查詢瘦身**: `fetch_competitor_review_queue_page()` 將原本 count + page 兩次重跑 review CTE 改成單次 SQL 的 `total_rows` + `paged_rows` 查詢,同步取得總數與頁面資料,降低 `/?filter=pchome_review``latest_momo` / `latest_attempt` / `valid_competitor` 的重複掃描;正式站小批次 rescore 入隊後,用於維持核心比價覆核頁可操作速度。
- **V10.443 PChome rescore 人工覆核入隊**: `scripts/audit_competitor_match_attempt_rescore.py --apply-accepted` 只會把最新版 matcher 已通過門檻的舊低信心候選追加為 `rescore_accepted_current` attempt進入商品看板人工覆核隊列不寫 `competitor_prices`、不寫 `competitor_price_history`,必須由操作員按「採用同款」後才正式更新 PChome 價差。Dashboard 補上「重算可採用待審」分流與狀態文案,避免安全回刷候選混在一般低信心項目裡。
- **V10.442 CI/CD legacy GitLab 探測降噪**: `/cicd` 舊 GitLab pipeline API 預設改為 disabled除非明確設定 `GITLAB_ENABLED=true` 並提供 `GITLAB_TOKEN`,否則不再打 `192.168.0.110:8929` 或 SSH fallback正式 responsive smoke 造訪 `/cicd` 時只呈現可診斷空狀態,不再把已退役 GitLab endpoint 的 connection refused / permission denied 寫成錯誤噪音。
- **V10.441 PChome matcher re-score audit**: 新增 read-only `competitor_match_attempt_rescore_audit` 服務與 `scripts/audit_competitor_match_attempt_rescore.py`,可針對既有 `competitor_match_attempts` 用最新版 matcher 重新分類成 `accepted_current` / `unit_comparable_current` / `identity_veto_current` / `low_score_current`,預設不寫 DB、不更新正式價格商品看板同步補蘭蔻/達特醫/hoi/Saugella/Lactacyd 等 focused matcher reason 中文標籤。正式抽樣中 31 筆舊 `strong_exact_spec_match` 低信心資料,最新版 matcher 可讀出 10 筆 gate pass、1 筆單位價、11 筆 hard veto、9 筆仍低信心,作為後續人工覆核與批次回刷前的安全量化。
- **V10.440 Mustela 爽身潤膚乳同款 anchor**: marketplace matcher 新增 `慕之幼爽身潤膚乳` identity anchor並讓標題中插入「加量版」時仍可抽出同一身份詞正式樣本 `【Mustela 慕之恬廊】慕之幼 加量版爽身潤膚乳 500mlX2入` vs `【慕之恬廊】慕之幼爽身潤膚乳(500毫升X2入)` 由 0.741 提升到 0.801,維持 `hard_veto=false`、人工 review 型態,不放寬全域門檻、不寫正式 `competitor_prices`
- **V10.439 外部 BI / 資料協作入口收斂**: `/metabase``/grist` 保持在 momo-pro 內部診斷 bridge不再出現空白頁或錯連其他專案`.env.example` 與 bi profile 的 Grist 預設 URL 改為 `https://mo.wooo.work/grist` / `GRIST_APP_HOME_URL`,測試同步守住 `grist.wooo.work``awoooi` 不再回到 app/template/env/compose 導覽設定。外部工具頁 H1 移除 viewport font scaling改用新版 token 與手機 media query。
- **V10.438 PPT QA 失敗重跑精準化**: `/observability/ppt_audit_history` 的 QA 失敗與 issue triage 卡片會從 PPT 檔名前綴推回原始 `report_type`,不再把所有視覺 QA 失敗硬編成 daily 重跑;單筆「重跑」會以 `force=true` 呼叫補齊 API並在產生前只失效同一 `report_type + parameters` 的 active `ppt_reports` cache避免重新產出仍命中舊簡報。頁面也把 audit lane 的預覽按鈕補上,讓失敗檔案可直接站內回放 PDF/PPTX 預覽。
- **V10.437 業績圖表載入韌性與 QA 升級**: `analysis-chart-theme.js` 的 Chart.js loader 加入 4.5 秒 timeout 與 jsDelivr → unpkg → cdnjs 三來源 fallback若外部 CDN 卡住或失敗,`/daily_sales``/growth_analysis` 會切到既有 HTML snapshot / fallback 圖表,不再留下空白圖表框。`check_sales_charts_runtime.js` 也從「canvas 有墨點」升級為檢查非零 dataset、可見元素、彩色資料筆跡與 canvas ink避免只有座標軸的假通過。
- **V10.436 daily_sales snapshot_date 型別修復**: `/daily_sales` 日期窗口查詢改為依 DB dialect 明確 castPostgreSQL 使用 `"snapshot_date"::date` 並把參數 `CAST(:start_date AS date)` / `CAST(:end_date AS date)`SQLite 使用 `date("snapshot_date")`metadata / fingerprint 查詢同步引用 cast 後日期,避免正式庫 `snapshot_date` 為 text 時出現 `text = date` / `text >= date` 類型錯誤。後台 `chart_generator_service.monthly_overview_chart()` 的月業績 SQL 也改為 `snapshot_date::date`,防止報表圖表因 text 欄位而空白。
- **V10.435 商品列 PChome 狀態診斷翻譯**: Dashboard 商品列的 `_build_pchome_match_status()` 補上 `makeup_finish_conflict``nail_tool_function_conflict``schick_razor_line_conflict``variant_selection_review` 等具體狀態文案;`_load_pchome_match_attempt_map()` 同步解析 `match_diagnostic_json` 產生 `diagnostic_reasons` / `diagnostic_reason_text`,讓 overview、覆核隊列、商品列表與 Excel 的診斷語意一致。
- **V10.434 PChome 人工覆核閉環補搜尋**: 商品看板 PChome review queue 新增「補搜尋」人工決策按鈕,對應 `needs_research``manual_needs_research``manual_rejected``manual_unit_price_required``manual_needs_research` 納入全部覆核隊列與「人工閉環」篩選,避免操作員按完否決/單位價/補搜尋後項目從列表消失、後續無法追蹤。
- **V10.433 PChome 覆核診斷標籤與 variant 回刷補強**: `competitor_intel_repository` 的 review queue / 商品看板 / Excel export 改為優先讀取 `match_diagnostic_json.reasons`,再 fallback 文字版 `error_message`;同步補 `makeup_finish_conflict``nail_tool_function_conflict``schick_razor_line_conflict``variant_descriptor_conflict` 等操作員可讀標籤,讓商品列表顯示「妝效質地不同、工具功能不同、除毛刀品線不同」而不是 raw machine code。matcher 另補 MUJI 精油芬香護手霜的 brandless exact recoveryPChome 標題缺品牌但身份詞與 50g 規格一致時可進 manual-review identityperipera 多色任選 vs 單一色號會標記 `variant_selection_review` 並留在 `true_low_confidence`,避免被誤列為可批次救回。
- **V10.432 近門檻比價 hard-veto 補強**: marketplace matcher 不放寬 `MIN_MATCH_SCORE`,針對正式 `true_low_confidence` 前段新增窄範圍防錯配M.A.C `MACximal` 柔霧唇膏 vs 緞光唇膏標記 `makeup_finish_conflict`、ERBE 指甲清垢棒 vs 指甲緣刨刀標記 `nail_tool_function_conflict`、Schick 舒芙 vs 舒綺仕女除毛刀標記 `schick_razor_line_conflict`,三者皆進 hard veto同時把 `潤膚乳` / `身體乳` / `嬰兒乳液` / `寶寶乳液` 納入乳液型別,讓慕之幼爽身潤膚乳等真同款回刷更穩定。新增測試鎖住 MUJI 護手霜、Mustela 慕之幼潤膚乳、Herbacin 小甘菊護手霜可 exact並確保高 variant 錯配不被 focused rule 推進。
- **V10.431 Telegram callback byte-safe**: `triaged_alert()``momo:eig:*` HITL callback 改為依 UTF-8 byte 長度截斷,不再用字元數截斷;中文或過長 `event.id` / `decision_envelope.decision_id` 仍會保留可追蹤 payload且保證 `callback_data` 不超過 Telegram 64-byte 限制,避免專業排版告警因 callback 太長而整則送出失敗。
- **V10.430 NemoTron 決策 callback 追蹤 ID 修補**: `NemoTronDispatcher._send_telegram()` 會把 `decision_envelope.decision_id` 提升為 EventRouter `event.id``triaged_alert()` 也會在上游缺 `event.id` 時改用 `decision_id` 產生 `momo:eig:*` callback避免價格決策通知的「忽略此事件」audit 落成 `unknown` 而無法追查。
- **V10.429 111 / NemoTron 治理回歸補齊**: 補齊 `.env.example` 中 111 circuit breaker、111 allowlist proxy、部署 smoke、資料庫與 Redis runtime keys並同步大檔 inventory 行數,讓完整測試可覆蓋最新 `V10.425``V10.428` 變更;此版不放寬商品比對門檻、不修改 `competitor_prices` 寫入規則。
- **V10.428 NemoTron 價格決策信封落地**: `NemoTronDispatcher``price_alert``human_review` 事件現在會產生 12 Agent 共用 `decision_envelope`把同款證據、價差、七日銷量變化、營收流失、建議行動、HITL guardrails、資料品質與 trace 同步寫入 EventRouter event 與 KM metadata這讓 Telegram、AI 觀測台、PPT QA 與後續 Agent 協作能讀同一份可稽核證據,而不是各自解析告警文字。
- **V10.427 111 fallback circuit breaker**: `OllamaService` 在選到 111 final fallback 前先讀 `ai_calls` 近 60 分鐘比例;若 Ollama 呼叫 >=20、111 >=5 且占比 >=5%,會短暫跳過 111 並清除 resolved host cache避免 111 在已偏高時繼續承接長任務。DB 觀測失敗採 fail-open避免觀測層故障反向中斷 GCP-A/GCP-B 正常路由。
- **V10.426 111 proxy 拒絕日誌去重**: `ollama111_allow_proxy.py` 對同一來源 IP 的 reject log 預設 60 秒去重,保留 110 / 121 被擋的可觀測性,同時避免旁路 VM 持續探測時把 111 的 proxy log 與磁碟 I/O 刷高。
- **V10.425 111 fallback 使用率護欄**: Scheduler 每 15 分鐘只讀 `ai_calls` 檢查 111 Ollama fallback 使用率,預設 60 分鐘內 Ollama 呼叫 >=20、111 呼叫 >=3 且占比 >=5% 才推 Telegram並列出 111 caller Top 5此護欄只觀測與告警不改路由、不寫 DB、不重啟服務讓 111 被異常承接高負載時可即早發現。
- **V10.424 111 proxy LaunchAgent 安裝路徑穩定化**: `install_ollama111_allow_proxy.sh` 會把 proxy script 複製到 `~/.local/share/momo-pro-system/ollama111_allow_proxy.py` 後再寫入 LaunchAgent避免 111 重啟或 iCloud repo 路徑未掛載時代理失效;同時清空舊 stderr log讓安裝後狀態更容易判讀。
- **V10.423 12 Agent 決策信封**: `triaged_alert()` 支援 `decision_envelope` 結構化區塊,讓 Hermes / NemoTron / OpenClaw / ElephantAlpha 與後續 12 角色決策統一輸出 `severity``evidence``recommended_action``expected_impact``confidence``guardrails``trace`;缺證據時必須明確標記資料品質與 HITL 邊界,避免再出現空泛效益預測或不可追溯告警。
- **V10.422 111 proxy LaunchAgent 持久化**: 新增 `scripts/ops/install_ollama111_allow_proxy.sh`,在 111 以 user LaunchAgent 安裝 `com.momo.ollama111-allow-proxy`,啟動時設定 `OLLAMA_HOST=127.0.0.1:11434`、重啟 Ollama、載入 allowlist proxy避免重開機或重新登入後 111 又回到 LAN 全開狀態。
- **V10.421 Kanebo Milano / hoi 蠟燭品類防錯配**: marketplace matcher 追加 `kanebo_milano_type_conflict``hoi_candle_line_conflict`,將 Kanebo Milano Collection 蜜粉餅 vs 絕色香水、hoi 日京山風香氛蠟燭 vs hoi!LAB 實驗室香氛蠟燭經典篇列為 hard veto同品牌、同系列字樣或同容量仍不可跨品類/跨產品線直接比價。
- **V10.420 111 Ollama LAN allowlist proxy**: 追查 111 高負載時確認來源不是 momo-pro而是 110 上 `awoooi-cd` 臨時測試與 121 VMware VM 直接打 `192.168.0.111:11434`,繞過 `ai_calls` 與 momo-pro router 載入 7B runner。新增 `scripts/ops/ollama111_allow_proxy.py`,將真實 Ollama 收斂到 `127.0.0.1:11434`,由 user-space proxy 綁 `192.168.0.111:11434` 並預設只允許 111 本機與 188 生產宿主110 / 121 會被 reset111 fallback 保留給 momo production。
- **V10.419 Dr.Hsieh LabSmart 精華品線防錯配**: marketplace matcher 追加 `dr_hsieh_labsmart_line_conflict`,只針對 Dr.Hsieh/達特醫的 `LabSmart Hi-Tech` / `LabSmart Classic` 精華被拿去對 `神經醯胺多重修復保濕精華液` 的近門檻錯配做 hard veto同品牌同容量但不同產品線不再因規格相同停在 `true_low_confidence` 或被誤推進比價。
- **V10.419 production pilot**: 正式回刷 SKU `10413050` / `10413051`,兩筆 Dr.Hsieh LabSmart 精華 vs 神經醯胺多重修復精華皆由 `true_low_confidence` 轉為 `identity_veto``diagnostic_codes=["dr_hsieh_labsmart_line_conflict"]``matched` 維持 1619、`true_low_confidence` 753→751、`identity_veto` 4011→4013無正式 `competitor_prices` 覆寫。
- **V10.418 bge-m3 一致性檢查不打 111**: `verify_embedding_consistency()` 預設只比對 GCP-A / GCP-B不再每週把 111 Mac 納入 bge-m3 背景驗證;新增 `EMBED_CONSISTENCY_INCLUDE_111=false` 預設,只有救急需要驗證 fallback 模型時才 opt-in。這補上 V10.417 後仍會由監測任務載入 111/GCP-B embedding runner 的缺口。
- **V10.417 Embedding/RAG 背景負載保護**: `OllamaService.generate_embedding()` 新增 `allow_111_fallback`、timeout cap、輸入長度 cap 與 `/api/embed keep_alive=1m`OpenClaw learning worker 與 RAG 查詢預設只跑 GCP-A → GCP-B不再把 `bge-m3` 背景 embedding / semantic RAG 轉嫁到 111。預設 `OLLAMA_EMBED_TIMEOUT=15``OLLAMA_EMBED_MAX_TIMEOUT=15``OLLAMA_EMBED_MAX_CHARS=4000`,避免 embedding worker 在 GCP-B/111 長時間常駐或拖住 runner。
- **V10.416 私密清潔 / 彩妝用途 / 棉棒 / 蘭蔻品線防錯配**: marketplace matcher 追加窄範圍 hard-veto guard讓 SAUGELLA 日用/加強 vs 黃金女郎型、Lactacyd 清新舒涼 vs 生理呵護、LUNASOL 頰彩 vs 眼彩、MUJI 細軸棉棒 vs 黑色棉棒、LANCOME 超極光晶露 vs 超極限肌因精華露不再停留在模糊 `true_low_confidence`,而是以 `*_variant_conflict` / `makeup_usage_conflict` / `lancome_line_conflict` 明確拒絕;不調整 `MIN_MATCH_SCORE`,也不放寬真同款進 matched 的門檻。
- **V10.416 production pilot**: 正式回刷 7 筆近門檻錯配樣本SAUGELLA 2 筆、LUNASOL 頰彩 vs 眼彩、LANCOME 超極光 vs 超極限、我的心機兒童防曬 vs 海洋友善防曬、Lactacyd 清新舒涼 vs 生理呵護、MUJI 細軸棉棒 vs 黑色棉棒皆更新為 `identity_veto``matched` 維持 1619、`true_low_confidence` 759→753、`recoverable_low_score` 1→0、`identity_veto` 4004→4011無正式 `competitor_prices` 覆寫。
- **V10.415 Hermes 預設不落 111 + 比對保護**: `OllamaService.generate()` 新增 `allow_111_fallback` 參數預設維持三主機相容Hermes intent / competitor analyst 改以 `HERMES_ALLOW_111_FALLBACK=false` 預設只跑 GCP-A → GCP-B兩台都不可用時交給規則引擎或 DB 證據 fallback不再把批量價格分析與意圖分類轉嫁到 111。同版 marketplace matcher 將防曬類列入 variant-sensitive排除 SPF/PA/UVA/UVB 這類規格 token 被誤當型號避免「兒童防曬乳」與「海洋友善保濕防曬乳」誤配Recipe Box 兒童防曬氣墊粉餅保留精準同品線例外;另新增 `pack_quantity_difference`,讓 Beauty Foot 足膜 5入 vs 4入走 unit comparable不再卡在低信心。
- **V10.415 production pilot**: 上線後以 SKU `12670442` 單筆回刷驗證 Beauty Foot 足膜 5入 vs 4入最新 attempt 由 `true_low_confidence` 轉為 `refresh_unit_comparable``diagnostic_codes` 補上 `pack_quantity_difference` / `unit_comparable``matched` 不增加、正式 `competitor_prices` 不覆寫;整體最新分布由 `true_low_confidence=760, refresh_unit_comparable=64` 變為 `true_low_confidence=759, refresh_unit_comparable=65`,符合「可單位價覆核但不可直接當同款總價告警」邊界。
- **V10.414 MCP fetch run readiness gate**: 新增 `mcp_fetch_run_readiness` read-only builder、GET/POST endpoint、UI run readiness 審核面板與 deployment readiness smoke target在 run package 後檢查 command preview、receipt path、artifact path、節流/timeout/dry-run-first 與操作員 shell-only 邊界API/UI 不執行 CLI、不抓外站、不寫檔、不開 DB、不掛 scheduler只放行到人工 shell dry-run 與後續 receipt gate。
- **V10.413 Code Review 預設保護 111 fallback**: production `ai_calls` 顯示 GCP-A 不可達時Code Review OpenClaw 會先耗掉 primary timeout再讓 GCP-B 撐到 60s最後落到 111 `llama3.2` 成功,造成 111 與 GCP-B 高負載。新增 `CODE_REVIEW_ALLOW_111_FALLBACK=false` 預設Code Review 的 Hermes LLM scan / OpenClaw assessment 只跑 GCP-A → GCP-B只有明確設 true 才把部署後重分析丟給 111。若 GCP-A/GCP-B 都失敗且 Claude/Gemini 未顯式開啟,改回 deterministic 本地降級摘要,不呼叫 Gemini也不再用 111 承接非即時重分析。
- **V10.412 MCP fetch run package gate**: 新增 `mcp_fetch_run_package` read-only builder、獨立 route extension、GET/POST endpoint、UI run package 審核面板與 deployment readiness smoke target將已通過的 target review 轉成操作員可覆核的 command argv preview 與 receipt path 契約API/UI 不執行 CLI、不抓外站、不寫檔、不開 DB、不掛 scheduler只放行到後續 run readiness review。
- **V10.411 rom&nd / Summers Eve / Solone 近門檻 review-only 回收**: marketplace matcher 追加三條窄範圍 focused identityrom&nd 果汁唇釉 2.0 catalog、Summers Eve 舒摩兒全肌防護浴潔露 2入、Solone 持久眼線筆;皆只進 `identity_review` / manual-review不直接價格告警。production pilot 已回刷 3/3`matched` 1616→1619、`true_low_confidence` 763→760rom&nd 染眉膏 ZO&FRIENDS 色號、Summers Eve 雙天王任選、Lactacyd 清新舒涼 vs 生理呵護、MAC 柔霧 vs 緞光、NIVEA / 曼秀雷敦包數差異仍不自動救回,維持準確率優先。
- **V10.410 Code Review timeout 梯度改為保護 111**: 部署後實測顯示 GCP-A 從 188 失聯時Code Review 仍會先等 primary 45sGCP-B 完整審查 prompt 又常因 25s 太短而 timeout最後轉落 111。`CODE_REVIEW_OLLAMA_TIMEOUT` 預設收斂為 `15s``CODE_REVIEW_OLLAMA_SECONDARY_TIMEOUT` 放寬為 `60s`Hermes LLM scan 若啟用則 primary `15s`、secondary `45s`。目標是 A 掛時更快讓位給 B並給 B 足夠時間完成,避免過早壓到 111。
- **V10.409 MCP fetch target review gate**: 新增 `mcp_fetch_target_review` read-only builder、GET/POST endpoint、UI target review 審核面板與 deployment readiness smoke target讓 manual fetch handoff 通過後,先審核 adapter registry 公開入口、每平台節流、樣本數、timeout 與 rollback planAPI/UI 不保存 payload、不發外部 request、不開 DB、不寫入、不掛 scheduler也不會自動打開 manual fetch。
- **V10.408 OPI 指甲油 catalog review-only 回收**: marketplace matcher 針對 OPI 類光繚指甲油加入同系列 catalog focused identity只在「白日夢遊」或「驕傲果凍」系列名雙方一致時進 `identity_review`12色/11色視為可選色號數差異不當作販售件數跨系列仍維持 suppress。production pilot 已回刷 KATE 怪獸級持色唇膏限量款與兩個 OPI SKU 共 3/3`matched` 1613→1616、`true_low_confidence` 766→763三筆皆為 `alert_tier_identity_review` / `price_basis_manual_review`,不進 Hermes 直接價格告警。
- **V10.407 Hermes/OpenClaw runner 熱駐留收斂**: V10.406 後續觀測顯示 GCP-B 仍會被 Hermes/OpenClaw 的 `24h` keep-alive runner 壓高 load導致 GCP-B generate timeout 後轉落 111。`HERMES_KEEP_ALIVE``OPENCLAW_STRATEGY_OLLAMA_KEEP_ALIVE` 改為 env 可控且預設 `5m`,並補測試禁止 OpenClaw strategy 再硬寫 `keep_alive="24h"`GCP-A 目前從 188 仍逾時,需另行修復主機/防火牆。
- **V10.406 Code Review Ollama keep-alive 收斂**: production audit 顯示 Gemini 24h 已為 0但 GCP-A `34.143.170.20:11434` 從 188 逾時、GCP-B 曾因多個 Ollama runner 長駐造成 generate timeout導致部署後 Code Review 轉落 111。`CODE_REVIEW_OLLAMA_KEEP_ALIVE` 預設由 `24h` 改為 `5m`,讓 GCP-B/111 的 code review runner 不再長時間常駐;實測已重啟 GCP-B Ollama 並確認 `gemma3:4b` 可於約 6.2s 完成短生成。
- **V10.405 MCP manual fetch handoff gate**: 新增 `mcp_manual_fetch_handoff` read-only builder、GET/POST endpoint、UI handoff package 審核面板與 deployment readiness smoke target讓 runtime promotion package 搭配操作員公開頁面、節流、無登入/反爬、無 DB、無 scheduler 確認後,只放行到人工 fetch gate operator reviewAPI/UI 不保存 payload、不打 health、不開 DB、不抓外站、不掛 scheduler也不會自動打開 manual fetch。
- **V10.404 Hermes 競價威脅漏斗只吃 direct alert**: `HermesAnalystService.fetch_candidates()``competitor_prices` JOIN 新增硬條件,只讓 `match_type=exact``price_basis=total_price``alert_tier=price_alert_exact` 的 identity_v2 配對進入 Hermes 競價威脅分析;`identity_review``unit_price_review``suppress` 仍保留在 dashboard / 人工覆核資料流,但不再消耗 Hermes token 或被上游視為直接價格威脅候選。production fresh 配對分布顯示直接告警約 497 筆、覆核型約 216 筆,本版將兩者在 AI 威脅入口切開。同版 matcher 追加 KATE 怪獸級持色唇膏、植村秀武士刀眉筆筆蕊、The Forest 焦糖楓葉擴香禮盒等近門檻 review-only 回收線,仍只進人工覆核,不直接價格告警。
- **V10.403 近門檻候選重驗擴池**: production 最新 72h attempt audit 顯示 7853 筆近門檻/被擋候選中,有 105 筆可被現行 matcher 回收,其中 46 筆已達 `price_alert_exact`、59 筆只進 `identity_review``CompetitorPriceFeeder._fetch_retryable_candidate_skus()` 擴大每日 revalidation 候選池,納入 `true_low_confidence``unit_comparable``refresh_unit_comparable` 與高分 `identity_veto`;但仍要求 PChome product_id、`best_match_score >= 0.70`,且正式寫入前必須由現行 matcher 重判、通過 hard-veto 與既有配對保護。
- **V10.402 catalog variant identity-review 回收**: marketplace matcher 新增 Johnsons 嬰兒潤膚乳 catalog 對同香型、IM MEME 涼感定妝噴霧、SO NATURAL FIXX 定妝噴霧三條 review-only focused identity讓同品線 catalog / variant 候選可脫離 `true_low_confidence` 但只進 `identity_review`,不直接價格告警;同版明確保留 MUJI 品牌缺漏護手霜等 brandless catalog 案例在低信心,避免品牌缺漏與多款任選同時存在時被過度救回。
- **V10.401 focused identity 邊界整理**: 將 Laundrin TOKYO 車用夾式消臭芳香劑判定抽成 `_has_laundrin_tokyo_car_freshener_alignment()`,並在 variant descriptor guard 中豁免同一條強身份線,避免 TOKYO / 車用 / 芳香劑語序差異造成誤擋。Yuskin 經典乳霜 30g 6 入組改用 `_has_exact_count_alignment()` 判斷包數,保留 6入 vs 6盒這類同數量但不同容器字詞的人工覆核路徑。
- **V10.400 氣墊粉餅補充蕊包數正規化**: marketplace matcher 針對氣墊粉餅新增保守的 `cushion_refill_pack_alignment`,只在一側明確為 `一盒兩蕊 / 2蕊`、另一側為單規格 `15g x2` 這類乘數包裝時,解除 `multi_component_conflict` 並進 `identity_review`。CLIO 羽緻無限緞光氣墊粉餅「一盒兩蕊」可被同款覆核;`2盒4蕊``15g x2` 仍維持 hard veto。同版補香氛蠟燭、TOKYO 車用消臭芳香劑、融蠟燈與有機護膚油 search identity anchors。離線 audit 759 筆 accepted 從 753 提升到 754剩餘 5 筆 fresh veto 皆為應擋的套組/品類差異。
- **V10.399 多香味 catalog 價格告警降級**: marketplace matcher 新增 `variant_selection_review`,當一側是無明確選項的商品線、另一側列出多個具名香味/款式選項時,允許同款身份回收但只進 `identity_review`,不直接進 `price_alert_exact`。首個正式案例是 HH 女性私密衣物抗菌手洗精 200ml 對 PChome 白麝香/清新花園/寶貝粉香多香味 listing此規則避免把多香味 catalog 價格誤當單一 variant 精準比價。
- **V10.398 true low confidence 保守回收**: marketplace matcher 針對正式前段 `true_low_confidence` 補一輪 focused exact identity lines讓 Baan 嬰兒修護唇膏、植村秀 3D 極細防水眼線膠筆、YSL 恆久完美透膚煙染腮紅、HH 私密植萃美白緊緻凝露、Lab52 學習刷牙漱口水、Benefit 經典菲菲染唇液、Herb24 晨霧純精油擴香儀、Pavaruni 40 香味 10ml 精油與 GATSBY 爆水擦澡濕巾等近門檻真同款可被回收;未放寬 `MIN_MATCH_SCORE`。同版保留 peripera 多色任選對單一色號、LUNASOL 頰彩對眼彩組、MUJI 細軸棉棒對黑色棉棒的低信心保護,並讓多組件套組即使達強身份證據也停在 `identity_review`,避免總價被誤當精準價格告警。
### 2026-05-21瀏覽器測試守門與 PChome 熱路徑優化
- **V10.397 離線 audit false negative 收斂**: marketplace matcher 針對 audit 剩餘 fresh bad 補三個保守修正:`200ml+200ml` 這類括號內規格串不再被計成額外組件Kiehls `1號護唇膏``1` 視為商品線名稱而非色號P.SHINE BEAUTY FOOT 雙面足部去硬皮磨砂棒以品牌 + 足部硬皮磨砂棒語意進 `identity_review`。同批補 focused exact identity lines讓 Biodance、SAB、LUSH、Kanebo、ARTMIS、Nailmatic、小浪、YUNMI、AQUIESSE、資生堂等低分但強證據同款被正確拉回高證據 exact 才可進 `price_alert_exact`,證據不足者仍進 `identity_review`。離線 audit fresh bad 從 9 降到 6剩餘皆為多組件/套組差異。
- **V10.396 多選 catalog 對 generic count 組合放行**: marketplace matcher 對「多款任選 catalog listing」對上同數量 generic `N入組` 候選新增保守豁免:需品牌、品類、基礎規格與數量一致,且 generic 端沒有具名色款/香味選項,才不觸發 `variant_option_conflict`。Johns Blend 香氛擴香罐 85g 任選 3 入 vs PChome 3入組會進 `identity_review`,不直接價格告警。
- **V10.395 離線競品身份 audit 工具**: 新增 `scripts/audit_competitor_identity_jsonl.py`,可把 production DB 匯出的 competitor identity JSONL 在本機重跑 current matcher輸出 accepted / veto / low-score / fresh bad 摘要與樣本;工具不連 DB、不寫 DB用來取代在 188 app container 內全量重掃造成的 memory 壓力。
- **V10.394 多色 catalog / 入門組防錯配**: marketplace matcher 補「琥珀橙 / 干邑棕 / 賽車綠」等車用香氛色款詞,當 MOMO 是多色/多款 catalog listing、PChome 是單一色款候選時會保留 `variant_option_conflict` hard veto同時把 `入門組` 納入套組詞,避免理膚寶水抗敏入門組被拿去跟單瓶乳液做總價比價。
- **V10.393 組合包 `+` 判定修正與 catalog 補強**: marketplace matcher 的組合包件數判定會先排除 `SPF50+``PA++++` 等防曬係數加號,以及 `NTT80+AL414` 這類純型號碼串,避免把防曬品與 OPI 套組的規格/型號加號誤判成多一個商品組件CeraVe 三件組 vs 兩件組仍維持 `multi_component_count_conflict` hard veto。同版收緊品牌 alias 判定,避免只有品牌名就觸發商品線加成,並補 Baan 貝恩嬰兒修護唇膏「原味/草莓」catalog listing 放行。
- **V10.392 組合包件數防錯配**: marketplace matcher 新增 `multi_component_count_conflict`,當 MOMO 與 PChome 都是 `+`/`` 組合包但組件數不同時直接進 `not_comparable`,避免三件組被拿去跟兩件組做總價告警;同步把該原因加入 evidence flags讓告警與審核畫面可以清楚顯示「組合包件數不同」。
- **V10.391 多款任選 catalog listing 防錯配**: marketplace matcher 新增 `catalog_variant_listing_alignment`,當 MOMO/PChome 雙方都是多款/多色/多香味任選 listing且商品線、規格與類型一致時可放行香氛擴香罐、香氛蠟燭等 catalog 型同款;同時把 Relove 菸鹼醯胺 vs 胺基酸私密清潔凝露列為變體衝突,並讓 competitor feeder 不再只因 `strong_exact_spec_match` 就把低分候選視為 recoverable避免只同規格但品線不同的商品回寫正式比價。
- **V10.390 PChome 近門檻商品比對規則**: marketplace matcher 補 17 組近門檻真同款召回與錯配防線,包含 OBgE 防曬棒、ARTMIS 私密清潔慕斯、Seche Vite 快乾亮油、TAICEND 屁屁噴、femfresh / VIGILL 私密清潔、Solone 眼部飾底乳、HYDSTO 車載香薰、小米 S101 刮鬍刀、PRAMY 定妝噴霧、I'M MEME 修容打亮棒、檜山坊滾珠精油、ARM&HAMMER 體香膏、Brush Baby WildOnes 電動牙刷與 Palmer's 按摩乳;同時把香氛/私密慕斯/定妝噴霧 finish 差異列為 variant-sensitive避免不同香味、蔓越莓 vs 金縷梅、柔焦霧面 vs 水光亮面被誤推成直接價格告警。
- **V10.388 精華乳 / 精華霜變體防錯配**: marketplace matcher 新增精華類 formulation conflict guard當共享 identity anchor 只到「精華」但一側是「精華乳」、另一側是「精華霜 / 精華液」時會標記 `variant_descriptor_conflict` 並壓低同款分數,避免自白肌等同品牌相近品線被錯推成 PChome/MOMO 可直接價格告警。Competitor feeder 同步會用最新 matcher 重新驗舊配對;若舊 `identity_v2` 已被現行 matcher 判成低分或 veto允許新的高信心候選替換避免歷史錯配卡住正式 `competitor_prices`
- **V10.387 EA 比價 HITL 告警證據排版**: Elephant Alpha 的 DB evidence 與 Hermes pre-fetch action 現在會把 PChome/MOMO 同款證據帶進 Telegram`match_type``price_basis``alert_tier``match_score` 會獨立成「證據」行,讓人工審核能分辨高信心同款、總價可比、單位價覆核與身份覆核,不再只看到乾巴巴的 `MOMO vs PChome` 長句。同版 marketplace matcher 補 Relove「私密潔淨凝露」identity anchor 與聯名款搜尋噪音,避免 PLAY BOY / 小虎等活動詞壓過真同款名稱。
- **V10.386 Gemini compose hard default / KATE 唇膏比對**: `docker-compose.yml` 針對 `momo-app``scheduler``telegram-bot` 明確釘住 `GEMINI_API_HARD_DISABLED=true``GEMINI_FALLBACK_ENABLED=false` 的預設,讓 `.env` 保留 API key 時也不會自動產生 Gemini 付費出站AI SOT 與 compose 測試同步鎖定此契約。同版 marketplace matcher 補 KATE/凱婷「柔霧裸唇膏」identity anchor避免 MOMO 長標含東京夜喫茶系列與任選文案時漏掉 PChome 同款短標。
- **V10.385 Lactacyd / MAQuillAGE 櫃別同款比對**: Marketplace matcher 補強 Lactacyd 私密潔浴露多款任選長標與 PChome 短標同款放行,並橋接「資生堂東京櫃」與 `MAQuillAGE 心機彩妝` 在「心機星魅蜜光圈潤唇膏」上的櫃別/品牌 alias避免真同款被 `brand_conflict` 擋掉。
- **V10.384 Karadium 無規格眼影棒同款放行**: Marketplace matcher 對 Karadium「閃亮珍珠眼影棒」新增品牌 + 強 identity anchor 加分,當 PChome 標題省略 1.4g 規格但品名/品牌高度一致、無變體衝突與 hard veto 時仍可進入 exact identity 告警候選,避免同款因規格缺字漏報。
- **V10.383 EA JSON fallback / EDM cache 自癒 / 比對別名補強**: Elephant Alpha 協調器現在可容忍 fenced JSON 與混文字 JSON若仍無法解析會改用 DB/Hermes 實證產生保守人工覆核決策,不再輸出舊式 OpenClaw 策略 plan 或自動調價暗示。EDM promo dashboard shared cache 遇到損毀 pickle 會自動刪除並重建,避免每個 worker 重複噴 `UnicodeDecodeError`。Marketplace matcher 補上 Curel/珂潤、Karadium 與兩個強 identity anchor 測試,降低真同款漏報。
- **V10.382 唇膏 exact identity 寬價差豁免**: marketplace matcher 對「同品牌 + 共享唇膏 identity anchor + 規格完全一致 + 無色號/變體衝突」的唇膏類商品,允許 sequence score 略低時仍套用 `price_penalty_suppressed_wide_exact_identity`;這只處理 PChome/MOMO 標題順序與行銷字差異造成的真同款漏報,不放寬顯性色號不同的 hard veto。
- **V10.381 browse.sh 比價診斷計畫**: PChome feeder 在 `no_result``no_match`、低信心、單位價覆核、既有配對保護與爬蟲錯誤時,會把 read-only `browse_diagnostic_json` 寫入 `competitor_match_attempts`,內含 PChome search URL 與建議 `browse get/open` 命令;正式排程仍 API-first`PCHOME_FEEDER_BROWSE_SH_EXECUTE_ENABLED=false` 預設不自動開瀏覽器,避免瀏覽器彈窗、登入或密碼提示干擾。
- **V10.380 111 Ollama final fallback 收斂**: 111 Mac fallback 從救急路徑改成更短的保護路徑,`OLLAMA_111_MAX_TIMEOUT` 預設由 45s 收緊到 20s並新增 `OLLAMA_111_NUM_PREDICT=512` 輸出上限;落到 111 時仍會降級重模型到 `llama3.2:latest`、縮 `num_ctx=4096``keep_alive=5m`,避免 GCP-A/GCP-B 短暫 timeout 後把長篇 Hermes/OpenClaw 工作轉嫁到 111 造成 swap 與 load 飆高。
- **V10.379 MCP runtime promotion gate**: 新增 `mcp_runtime_promotion` read-only builder、GET/POST endpoint、UI promotion package 審核面板與 deployment readiness smoke target將 MCP activation evidence 與 runtime smoke receipt 合併審核,讓 completion audit 的 runtime 缺口可由人工收據明確補齊。
- **V10.379 只讀安全邊界**: 本階段不保存 payload、不打 health、不開 DB、不抓外站、不掛 scheduler也不會因 promotion 通過自動打開人工 fetch gate正式 fetch / DB write / scheduler attach 仍需各自獨立 gate。
- **V10.378 AI 推薦頁首屏 Gemini 防漏**: `/ai_recommend` 首屏狀態快照新增 provider sanitization即使舊 cache / env 內出現 `default_provider='gemini'``recommended_provider='gemini'`,也會回到 `ollama`,避免 UI 把 Gemini 顯示成主推薦路徑;`/api/ai/set_provider` 同步正規化 provider 輸入,保留 Gemini 只能作 Ollama 失敗備援的拒絕訊息。
- **V10.377 Gemini 主路徑防漏補強**: `AIProviderService._get_recommended_provider()` 不再於 Ollama 不通時推薦 `gemini` 作為主提供者;`llm_model_router``ea_engine` 即使 caller 傳入 `gemini-2.0-flash` default也會改回 `hermes3:latest`,需要深推理才升 `deepseek-r1:14b``ElephantAlphaOrchestrator` 的 OpenClaw registry / system prompt 改為 Ollama-first避免 L3 HITL prompt 繼續把 Gemini 當主模型描述。同步補 AI SOT 與防回歸測試。
- **V10.376 Recipe Box 同款防曬漂移比對**: `services/marketplace_product_matcher.py` 對 Recipe Box 多效提亮防曬霜新增 shared identity anchor 加分,當 MOMO 長標含兒童/無毒/天然彩妝等行銷詞、PChome 以「韓兔 多效提亮防曬霜」呈現時仍可判定同款;同步測試鎖住 `shared_identity_anchor_recipe_box_line`,避免平台名稱漂移讓同款價格告警漏報。
- **V10.375 過期活動爬蟲排程 opt-in**: `run_scheduler.py` 將固定 LPN 的 `edm_task` / `festival_task` 改為 `MOMO_ENABLE_LEGACY_EDM_SCHEDULE=true` 才註冊,季節活動 `mothers_day_2026` / `valentine_520_2026` / `labor_day_2026` 改為 `MOMO_ENABLE_SEASONAL_PROMO_SCHEDULE=true` 才註冊;`services/data/crawler_config.json` 同步暫停已失效的 mothers_day LPN避免 scheduler 定時打過期 MOMO 活動頁造成 Selenium browser loop 與無效負載。手動 API / CLI 指定 LPN 仍保留;同版整合 NIVEA/OPI 等比價搜尋 noise 與 identity anchor 補強。
- **V10.374 EDM 失效頁告警止血**: `scheduler.py` 新增 MOMO EDM alert guard`run_edm_task` / `run_festival_task` / `run_promo_event_task` 遇到「很抱歉此EDM不存在」時會接受 browser alert、寫入 `Skipped / edm_unavailable` stats且不再送 EventRouter failure避免 festival / mothers_day 過期活動頁重新累積 Telegram queue同版整合 REJURAN 麗駐蘭唇膏同款在價格比過寬時的 exact-identity 價格懲罰豁免。
- **V10.373 PChome 同款名稱漂移整合**: 整合並修正 concurrent matcher work新增 MAC/M.A.C 品牌 alias、Yuskin 經典乳霜 4入/4盒組同數量 bundle equivalent、AHC 瞬效 B5 玻尿酸關鍵字重排 anchor修復 `_count_score()` 縮排破壞與 unreachable code讓新增測試可穩定通過。
- **V10.372 Smoke 與 EventRouter queue 修復**: 修正 AI automation smoke 對 NemoTron fallback 的 class 判斷,改接受實際存在的 `NemotronDispatcher._hermes_rule_fallback`,避免 Hermes fallback 正常卻被誤報 criticalEventRouter 失敗佇列回放改為重建短版 HTML-safe 訊息escape 標題/摘要/trace/error 並限制長度,避免舊 Selenium stacktrace 的 `<unknown>` 造成 Telegram HTTP 400 反覆卡住;同版整合 LUDEYA 蜂王玫瑰商品線在 MOMO/PChome 名稱漂移時的 identity anchor alias。
- **V10.371 品牌缺失同款放行**: marketplace matcher 新增 `brandless_exact_identity` 加分,只限「一側有品牌、一側缺品牌」但 shared identity anchor 夠長、規格/序列/中文名相似度都高且無 hard veto 的案例;覆蓋小米有品小浪智能感應自動噴香機,讓 PChome 標題省略品牌時仍可進入同款告警候選。
- **V10.370 Gemini runtime sentinel**: AI automation smoke 新增 `Gemini 出站費用 sentinel`,每天檢查近 24h `ai_calls.provider='gemini'` 的 calls/tokens/cost/top callers`GEMINI_API_HARD_DISABLED=true` 仍有 Gemini 記錄smoke 直接升為 critical。scheduler 09:10 摘要推播前會先執行一次只讀 smoke讓 Gemini 費用異常不再依賴人工打開 `/ai_automation_smoke` 才被發現。
- **V10.369 Gemini 防復發測試與極端價差同款放行**: 新增靜態測試禁止 production code 在 `services.gemini_guard` / `config.py` 之外直接讀 `GEMINI_API_KEY`,並要求所有 Gemini SDK/REST 出站點必須經 `get_gemini_api_key()`;比價 matcher 針對「同品牌 + 明確 identity anchor + 規格完全一致」但競品價格極端偏低的原生露/眉筆案例抑制價格懲罰,避免真同款因價格差被錯降級,同時補回既有 hard-veto 安全斷言。
- **V10.368 比價搜尋錨點強化**: marketplace matcher 補 LUDEYA 蜂王玫瑰外泌微臻霜、雅詩蘭黛微分子肌底原生露、Za / PERIPERA 眉筆眉彩等低信心邊界品牌的 identity anchor並把「兩入組 / 任選色號 / 多色可選 / 櫻花輕盈版」歸為搜尋噪音,讓 MOMO → PChome 搜尋詞更聚焦於同款身份與規格,不被包裝組合或色號選項帶偏。
- **V10.367 Gemini hard egress kill switch**: 新增 `GEMINI_API_HARD_DISABLED=true` 預設硬封鎖,中央 `services.gemini_guard` 會在 hard switch 未解鎖時拒絕 `GEMINI_API_KEY`,即使 `GEMINI_FALLBACK_ENABLED=true` 也不會初始化 SDK 或 REST 出站。Code Review/OpenClaw/MCP/通用 AI fallback 保留 emergency path但必須同時設 `GEMINI_API_HARD_DISABLED=false``GEMINI_FALLBACK_ENABLED=true`,必要時再用 `GEMINI_ALLOWED_CONTEXTS` 限定 caller。
- **V10.366 MCP runtime smoke receipt review**: 新增 `mcp_runtime_smoke_receipt` read-only builder、GET/POST endpoint、UI receipt JSON 審核面板與 deployment readiness smoke target讓操作員貼上 `/api/market_intel/mcp_readiness?execute=true&timeout=3` 的實際收據後,判斷 external/internal MCP runtime 是否可升級為已驗收。
- **V10.366 只讀安全邊界**: 本階段不保存 payload、不打 health、不開 DB、不抓外站、不掛 scheduler若收據含 DB write/commit/scheduler/writes 旗標或原始 readiness blocked reasons會直接阻擋。
- **V10.365 專業比價分級連動**: MOMO/PChome matcher 新增 `match_type``price_basis``alert_tier` 與 evidence flags將「高信心同款 / 同商品不同包裝 / 同系列不同款 / 可比但需覆核 / 非同款」寫入 diagnostics 與 tagsfeeder、競價情報 repository、Hermes payload、NemoTron 派發與 Telegram 告警格式同步讀取同一份分級。NemoTron 也新增硬閘門:非 `exact + total_price + price_alert_exact` 的項目即使模型回傳 price alert也會改走人工覆核避免不同包裝或同系列不同款被直接建議降價。
- **V10.364 111 context cap**: 111 fallback 即使降到 `llama3.2:latest`Ollama 仍可能用 131k context 啟動 runner導致 3B 模型也吃到 10GB+;新增 `OLLAMA_111_NUM_CTX=4096`,落到 111 時強制縮 context並把 `llama3.2:latest` 加入零成本模型表,避免觀測台 unknown model warning。
- **V10.363 Dashing Diva variant-safe search**: PChome/MOMO matcher 針對 Dashing Diva 美甲片補「商品頁目錄有 30片/盒、MOMO 標題省略片數」的安全豁免,只限同品牌、同美甲片線、同具名款式錨點;搜尋詞也優先帶出 `月影柔霧``銀絲柔彩` 等款式名,降低同系列不同款式互撞。
- **V10.362 111 fallback shrink-to-3B**: 111 Mac 實測 `hermes3` / `qwen2.5-coder` 雖是 7B/8B但 large context runner 仍會佔用 6-10GB RSS 並推高 swap111 fallback 改為所有 7B+、vision 與 long-context 文字生成都降級到 `llama3.2:latest``ai_calls.model` 也會記錄實際降級模型並把原請求模型放入 `meta.requested_model`
- **V10.361 111 fallback resource guard**: 實測 111 Mac 高 load 主要來自 Codex app / WindowServer 前台負載,且 Ollama 曾因 fallback 載入 `qwen3:14b` 造成 16GB RAM / swap 壓力;已手動 unload 111 上的重模型,並讓 `OllamaService.generate()` 落到 111 時自動把 14B+ 模型降到 `OLLAMA_111_MODEL_FALLBACK``keep_alive` 縮至 `OLLAMA_111_KEEP_ALIVE=5m`、timeout 封頂 `OLLAMA_111_MAX_TIMEOUT=45`。GCP-A/GCP-B 仍可跑 `qwen3:14b`111 只做短時最後備援。
- **V10.360 browser smoke guard**: `tests/test_image_fetch.py` 改為預設 skip只有 `RUN_MOMO_BROWSER_TESTS=1` 才會打開外部 MOMO 網站;手動執行時預設 headless並關閉 Chrome password manager/autofill避免一般 pytest 觸發瀏覽器與密碼允許提示。
- **Scheduler Selenium 防彈窗**: `managed_scraper_resources()``credentials_enable_service=false``profile.password_manager_enabled=false` 與 Autofill/PasswordManager feature disable降低背景 Selenium 觸發密碼管理提示的機率。
- **PChome dashboard hot path**: `competitor_intel_repository.py` 的 coverage / review queue 最新 MOMO 價格查詢改用 `JOIN LATERAL ... ORDER BY pr.timestamp DESC, pr.id DESC LIMIT 1`,避免 window function 掃描造成首頁與覆核隊列熱路徑變慢Dashing Diva 召回搜尋補品線與 `magicpress` broad terms。
### 2026-05-21Browse.sh 爬蟲診斷與 PChome 色號比對強化
- **V10.359 Browse.sh optional diagnostics**: 新增 `services/browse_sh_tool.py``scripts/tools/browse_sh_probe.py`,可檢查或執行 `browse` CLI目前只定位為 MOMO/PChome selector、XHR 與 network trace 探勘,不進 scheduler 主路徑,也不直接寫正式競品價格。
- **MOMO/PChome matcher 色號防錯配**: `marketplace_product_matcher.py` 補護甲油、洗手慕斯、足膜精準搜尋,搜尋詞保留 `4.2ml` 這類小數規格;唇釉、妝前乳、素顏霜等顯性色號/色系不一致時會 hard veto避免同系列不同色號被推成正式價差。
- **導入限制**: 本機 Node 16 目前因 `icu4c` 動態庫缺失無法啟動browse.sh 需待 Node 修復或於乾淨主機安裝後才可實跑repo 內先保留 optional wrapper、測試與 playbook。
### 2026-05-21市場情報 MCP 啟用證據審核
- **V10.358 MCP activation evidence review**: 新增 `mcp_activation_evidence` read-only builder、GET/POST endpoint、UI redacted evidence 審核面板與 deployment readiness smoke target讓操作員貼上 env/health/router/telemetry/fallback 證據後判斷能否補齊 external/internal MCP runtime 缺口。
- **只讀安全邊界**: 本階段不保存 payload、不打 health、不啟動 MCP、不執行 docker/SSH、不開 DB、不抓外站、不掛 schedulerpayload 只允許 redacted/boolean真實 secret 字串與任何 DB write/fetch/scheduler 證據會被阻擋。
### 2026-05-21市場情報 MCP 完整度稽核
- **V10.357 MCP completion audit**: 新增 `mcp_completion_audit` read-only builder、GET endpoint、UI 面板與 deployment readiness smoke target彙整外部 MCP design/runtime、內部 tool contract/runtime、activation runbook 與 fetch gate 狀態。
- **只讀安全邊界**: 本階段只做完整度稽核,不啟動 MCP、不打 health、不執行 docker/SSH、不開 DB、不寫檔、不抓外站、不掛 scheduler外部 MCP runtime complete 仍需 operator 依 runbook 啟用與 health 驗證。
### 2026-05-21市場情報 Telegram dispatch report catalog record final closeout gate
- **V10.356 report catalog record final closeout gate**: 新增 `candidate_queue_review_ai_summary_persistence_telegram_dispatch_report_catalog_record_final_closeout` service、POST endpoint、UI 按鈕與 deployment readiness smoke target在 archive summary gate 後覆核 catalog record identity、artifact traceability、sections、DB commit/post-write smoke、pipeline complete 與無後續 follow-up。
- **只讀安全邊界**: 本階段是 catalog record pipeline terminal previewAPI/UI 不讀 approval/Telegram token、不呼叫 LLM、不產報表、不派送 Telegram、不開 DB、不寫檔、不執行 CLI、不寫 catalog record、不 commit、不更新 `review_state`、不掛 scheduler。
### 2026-05-21市場情報 Telegram dispatch report catalog record archive summary gate
- **V10.355 report catalog record archive summary gate**: 新增 `candidate_queue_review_ai_summary_persistence_telegram_dispatch_report_catalog_record_archive_summary` service、POST endpoint、UI 按鈕與 deployment readiness smoke target在 archive gate 後整理 catalog record identity、artifact traceability、DB commit/post-write smoke、archive manifest/retention policy 與後續 final closeout separate gate。
- **只讀安全邊界**: 本階段只放行到後續 report catalog record final closeout gateAPI/UI 不讀 approval/Telegram token、不呼叫 LLM、不產報表、不派送 Telegram、不開 DB、不寫檔、不執行 CLI、不寫 catalog record、不 commit、不更新 `review_state`、不掛 scheduler。
### 2026-05-21市場情報 Telegram dispatch report catalog record archive gate
- **V10.354 report catalog record archive gate**: 新增 `candidate_queue_review_ai_summary_persistence_telegram_dispatch_report_catalog_record_archive` service、POST endpoint、UI 按鈕與 deployment readiness smoke target在 closeout gate 後審核 closeout/commit/run receipt/writer output/post-write smoke/backup 封存證據、archive manifest/retention policy 與後續 archive summary separate gate。
- **只讀安全邊界**: 本階段只放行到後續 report catalog record archive summary gateAPI/UI 不讀 approval/Telegram token、不呼叫 LLM、不產報表、不派送 Telegram、不開 DB、不寫檔、不執行 CLI、不寫 catalog record、不 commit、不更新 `review_state`、不掛 scheduler。
### 2026-05-20市場情報 Telegram dispatch report catalog record closeout gate
- **V10.353 report catalog record closeout gate**: 新增 `candidate_queue_review_ai_summary_persistence_telegram_dispatch_report_catalog_record_closeout` service、POST endpoint、UI 按鈕與 deployment readiness smoke target在 commit gate 後審核 catalog record identity、DB commit/post-write smoke 證據、操作員 closeout 確認與後續 archive separate gate。
- **只讀安全邊界**: 本階段只放行到後續 report catalog record archive gateAPI/UI 不讀 approval/Telegram token、不呼叫 LLM、不補產報表、不派送 Telegram、不開 DB、不寫檔、不執行 CLI、不寫 catalog record、不 commit、不更新 `review_state`、不掛 scheduler。
### 2026-05-20市場情報 Telegram dispatch report catalog record commit gate
- **V10.352 report catalog record commit gate**: 新增 `candidate_queue_review_ai_summary_persistence_telegram_dispatch_report_catalog_record_commit` service、POST endpoint、UI 按鈕與 deployment readiness smoke target在 run receipt 後審核外部 CLI catalog record DB commit、post-write smoke、操作員 commit gate 確認與後續 closeout separate gate。
- **只讀安全邊界**: 本階段只放行到後續 report catalog record closeout gateAPI/UI 不讀 approval/Telegram token、不呼叫 LLM、不補產報表、不派送 Telegram、不開 DB、不寫檔、不執行 CLI、不寫 catalog record、不 commit、不更新 `review_state`、不掛 scheduler。
### 2026-05-20市場情報 Telegram dispatch report catalog record run receipt
- **V10.351 report catalog record run receipt**: 新增 `candidate_queue_review_ai_summary_persistence_telegram_dispatch_report_catalog_record_run_receipt` service、POST endpoint、UI 按鈕與 deployment readiness smoke target在 run readiness 後審核外部 CLI writer output、catalog record key/hash、DB commit receipt 與 post-write smoke。
- **只讀安全邊界**: 本階段只放行到後續 report catalog record commit gateAPI/UI 不讀 approval/Telegram token、不呼叫 LLM、不補產報表、不派送 Telegram、不開 DB、不寫檔、不執行 CLI、不寫 catalog record、不 commit、不更新 `review_state`、不掛 scheduler。
### 2026-05-20市場情報 Telegram dispatch report catalog record run readiness
- **V10.348 report catalog record run readiness**: 新增 `candidate_queue_review_ai_summary_persistence_telegram_dispatch_report_catalog_record_run_readiness` service、POST endpoint、UI 按鈕與 deployment readiness smoke target在 run package 後檢查 payload manifest、manual CLI command、backup/dry-run、run receipt 與 postwrite smoke 條件。
- **只讀安全邊界**: 本階段只放行到後續 report catalog record run receipt gateAPI/UI 不讀 approval/Telegram token、不呼叫 LLM、不補產報表、不派送 Telegram、不開 DB、不寫檔、不執行 CLI、不寫 catalog record、不更新 `review_state`、不掛 scheduler。
### 2026-05-20市場情報 Telegram dispatch report catalog record run package
- **V10.347 report catalog record run package**: 新增 `candidate_queue_review_ai_summary_persistence_telegram_dispatch_report_catalog_record_run_package` service、POST endpoint、UI 按鈕與 deployment readiness smoke target在 record write gate 後整理 payload manifest、CLI command bundle、backup/dry-run trace 與後續 run readiness separate gate。
- **只讀安全邊界**: 本階段只放行到後續 report catalog record run readiness gateAPI/UI 不讀 approval/Telegram token、不呼叫 LLM、不補產報表、不派送 Telegram、不開 DB、不寫檔、不執行 CLI、不寫 catalog record、不更新 `review_state`、不掛 scheduler。
### 2026-05-20市場情報 Telegram dispatch report catalog record write gate
- **V10.344 report catalog record write gate**: 新增 `candidate_queue_review_ai_summary_persistence_telegram_dispatch_report_catalog_record_write` service、POST endpoint、UI 按鈕與 deployment readiness smoke target在 catalog write preflight 後檢查 catalog record key/schema/hash trace、operator dry-run、backup 與 commit separate gate。
- **只讀安全邊界**: 本階段只放行到後續 report catalog record run package gateAPI/UI 不讀 approval/Telegram token、不呼叫 LLM、不補產報表、不派送 Telegram、不開 DB、不寫檔、不寫 catalog record、不更新 `review_state`、不掛 scheduler。
### 2026-05-20市場情報 Telegram dispatch report catalog write preflight
- **V10.342 report catalog write preflight gate**: 新增 `candidate_queue_review_ai_summary_persistence_telegram_dispatch_report_catalog_write_preflight` service、POST endpoint、UI 按鈕與 deployment readiness smoke target在 report catalog index 後整理 catalog record identity、write source trace、record schema preflight 與 runtime safety。
- **只讀安全邊界**: 本階段只放行到後續 report catalog record write gateAPI/UI 不讀 approval/Telegram token、不呼叫 LLM、不補產報表、不派送 Telegram、不開 DB、不寫 catalog preflight file、不寫 catalog record、不更新 `review_state`、不掛 scheduler。
### 2026-05-20市場情報 Telegram dispatch report catalog index
- **V10.339 report catalog index gate**: 新增 `candidate_queue_review_ai_summary_persistence_telegram_dispatch_report_catalog_index` service、POST endpoint、UI 按鈕與 deployment readiness smoke target在 report catalog handoff 後整理 catalog index identity、handoff source trace、index manifest 與 runtime safety。
- **只讀安全邊界**: 本階段只放行到後續 report catalog write preflight gateAPI/UI 不讀 approval/Telegram token、不呼叫 LLM、不補產報表、不派送 Telegram、不開 DB、不寫 catalog index file、不寫 catalog record、不更新 `review_state`、不掛 scheduler。
### 2026-05-20市場情報 Telegram dispatch report catalog handoff
- **V10.338 report catalog handoff gate**: 新增 `candidate_queue_review_ai_summary_persistence_telegram_dispatch_report_catalog_handoff` service、POST endpoint、UI 按鈕與 deployment readiness smoke target在 report archive summary 後整理 catalog identity、artifact manifest、section keys 與 hash traceability。
- **只讀安全邊界**: 本階段只放行到後續 report catalog index gateAPI/UI 不讀 approval/Telegram token、不呼叫 LLM、不補產報表、不派送 Telegram、不開 DB、不寫 catalog record、不更新 `review_state`、不掛 scheduler。
### 2026-05-20市場情報 Telegram dispatch report archive summary
- **V10.335 report archive summary gate**: 新增 `candidate_queue_review_ai_summary_persistence_telegram_dispatch_report_archive_summary` service、POST endpoint、UI 按鈕與 deployment readiness smoke target在 report archive 後整理 report identity、archive traceability、integrity review 與 runtime safety sections。
- **只讀安全邊界**: 本階段只放行到後續 report catalog handoff gateAPI/UI 不讀 approval/Telegram token、不呼叫 LLM、不補產報表、不派送 Telegram、不開 DB、不寫檔、不更新 `review_state`、不掛 scheduler。
### 2026-05-20PChome 核心比價準確率與補抓可觀測性
- **V10.334 MOMO/PChome matcher 強化**: 補常見品牌 alias 與任選/平輸/國別 noise 收斂,並加入刀把/刀片/刀頭件數解析、同品牌不同系列硬否決,避免為了提高覆蓋率把 Gillette/Schick 等不同系列錯配成同款。
- **近門檻候選重新評分**: `CompetitorPriceFeeder` 新增 `run_retryable_candidate_revalidation()`,優先重評舊 `low_score` 中 0.70 以上、非 hard veto 且有 PChome product_id 的候選,再補抓高價未配對商品;排程與手動 API 都會納入這段流程。
- **PChome 補抓產線狀態**: 商品看板新增 PChome backfill status card後端以 JSON 狀態檔記錄 queued/revalidating/matching/generating_picks/clearing_cache/completed/failed、結果統計與最近 run避免手動補抓後沒有進度與錯誤上下文。
### 2026-05-20重開機後首頁熱路徑索引持久化
- **Dashboard / PChome 慢查詢修復**: 主機重開機後 `https://mo.wooo.work/` 首頁可用但多次逾時,實際瓶頸集中在首頁與 PChome coverage 查詢掃描 `products``price_records``competitor_match_attempts`。線上先補三個索引讓首頁恢復 200並新增 `migrations/040_dashboard_hot_path_indexes.sql` 將修復持久化到 fresh restore / DB rebuild 流程。
- **Growth Analysis 冷快取修復**: `/growth_analysis``monthly_summary_analysis` 落後時會改掃 `realtime_sales_monthly` 聚合,冷計算約 14 秒;修正為 source fingerprint 未變時延長共享快取有效期,匯入流程仍主動清除快取,避免資料未變卻反覆掃大表。
- **PChome backfill pilot**: V10.328 diagnostics 欄位上線後先跑小批次,刷新過期 identity_v2 30 筆11 筆成功更新)、高價未配對 15 筆全被低信心/單位價擋下;樣本確認多數 hard veto 正確,另補 `strong_component_line_match` 處理 Gennies 類同品牌完整多組件套組。
### 2026-04-29ADR-017 Phase 3f 模組化收尾啟動
- **DB metadata 救急**: `database/manager.py` 改為顯式載入 permission / AI / autoheal / import / vendor / realtime_sales ORMPostgreSQL 初始化透過 process-local guard + advisory lock 執行 `Base.metadata.create_all()`,避免新環境漏表與一般流量重複碰 DDL。
- **realtime_sales_monthly 補 ORM**: 新增 `database/realtime_sales_models.py`,並同步 `docker/postgres/init/01-init.sql` 欄位,避免 fresh volume 先建出窄表後造成匯入欄位靜默遺失。

View File

@@ -0,0 +1,79 @@
# AI 觀測台 UI QA Guardrails2026-05-05
## 背景
Claude Code Phase 38→55 完成 AI 觀測台 10 頁,但前端曾出現以下問題:
- 側欄第二/三層字色太暗,看不清楚。
- 側欄背景回退成近純黑,偏離暖咖啡設計規範。
- 觀測台頁面 typography / spacing / button / table / chart 容器不一致。
- `observability-system.css` 在 template 有 link但 production `/static/css/observability-system.css` 曾 404。
- 前端互動曾外露 `Error: ...``unknown`、SQL/Jinja raw error 類文案。
## 現行治理入口
- UI 規範 guide`docs/guides/observability_ui_governance.md`
- 部署 SOP`docs/guides/deployment_sop.md`
- 頁面契約 SOT`scripts/observability_contract.py`
- 靜態 UI guard`scripts/check_observability_ui.py`
- Production smoke`scripts/check_observability_pages.py`
- 一鍵 QA`scripts/check_observability_suite.sh`
- CSS mirror sync`scripts/sync_observability_css.py`
- 渲染後視覺契約:`scripts/check_observability_visual_contract.sh`
## 必跑指令
修改觀測台 template、route、shell、topbar、CSS 後:
```bash
./scripts/quick_review.sh --sync-observability-css
./scripts/quick_review.sh --check-observability-css
./scripts/quick_review.sh --observability-qa
```
指定環境、渲染後視覺契約或只跑靜態 guard
```bash
./scripts/quick_review.sh --observability-smoke --base-url https://mo.wooo.work --timeout 12
./scripts/quick_review.sh --observability-qa --base-url https://mo.wooo.work
./scripts/quick_review.sh --observability-qa --skip-production
./scripts/quick_review.sh --observability-visual --base-url http://127.0.0.1:5016 --timeout 20
./scripts/quick_review.sh --observability-help
```
等效直接指令:
```bash
python3 scripts/sync_observability_css.py
python3 scripts/sync_observability_css.py --check
bash scripts/check_observability_suite.sh
bash scripts/check_observability_visual_contract.sh --base-url http://127.0.0.1:5016 --timeout 20
```
## 重要陷阱
- `static/css/observability-system.css` 是 canonical CSS。
- `web/static/css/observability-system.css` 是 Flask production static route 實際服務用 mirror。
- 兩者必須 byte-identicalguard 會檢查,不一致時跑 `sync_observability_css.py`
- Production smoke 必須看到 `觀測台 CSS: HTTP 200, markers=ok`
- 觀測台頁面清單、URL、`active_page`、內容 marker 不要分散維護,先改 `scripts/observability_contract.py`
- `quick_review.sh --observability-qa` 預設打 production `https://mo.wooo.work`;測 staging/localhost 時要明確帶 `--base-url`
- `quick_review.sh --observability-visual` 也預設打 production驗證尚未部署的本機變更時必須先啟 Flask local server 並明確帶 `--base-url http://127.0.0.1:<port>`。若打 production 失敗,先確認正式端是否已部署該版,不要把舊版正式站結果誤判成本機 diff 失敗。
- Gitea CD 會偵測觀測台 template/CSS/route/QA script/guide 變更deploy 前跑 CSS mirror check + static QAdeploy 後跑 production smoke。QA script 範圍包含 `quick_review.sh``check_observability_*``observability_contract.py``sync_observability_css.py`。CD 不會偷偷修 mirror若 check fail先本地跑 sync 後提交。
- CD 觸發判斷集中在 `scripts/check_observability_deploy_gate.py`;不要在 `.gitea/workflows/cd.yaml` 另維護一份長 regex。
- `check_observability_suite.sh` 會跑 deploy gate self-test確認觀測台相關檔案會觸發 QA、一般 backend/docs 檔案不會誤觸發。
## 已鎖住的回歸
- Times / Georgia / serif 標題字型。
- 超大 hard-coded clamp title。
- 圖表 inline `style="height:..."`
- 靜態 inline width。
- 純白 hover/card surface。
- raw SQL/Jinja exception 外露。
- raw `alert('Error: ...')` / `unknown` 前端文案。
- 側欄純黑背景。
- 側欄第二/三層低對比文字。
- 觀測台 URL 有側欄連結但 Flask route 不存在。
- 觀測台頁面 200 但內容 marker 缺失。
- CSS link 存在但 production static asset 404。

View File

@@ -0,0 +1,32 @@
# Phase 38→56 AI 觀測台戰役盤點
> 日期2026-05-05
> 用途接續觀測台、Telegram、scheduler probe、L2 自動化與 deploy_doctor 時的低成本入口。
## 已確認落地
- Commit 19f1340→df2311d 覆蓋 Phase 38→55HEAD 另有 Phase 56 deploy_doctor 擴充。
- Web 觀測台已形成 10 頁overview、agent_orchestration、business_intel、host_health、ai_calls、budget、promotion_review、rag_queries、quality_trend、ppt_audit_history。
- `templates/components/_ewoooc_shell.html` 已加入 AI 觀測 sidebar group`templates/ewoooc_base.html` 已加入 topbar health indicator。
- Telegram 已加入 `obs_*` 指令與 `cmd:obs_heal:*``cmd:obs_force_throttle``cmd:obs_trigger_review` inline action。
- `run_scheduler.py` 已加入 host probe、cleanup、AI error spike、observability daily summary。
- `migrations/029_create_host_health_probes.sql``migrations/030_create_ppt_audit_results.sql` 已補 host health / PPT audit 持久化。
## 2026-05-05 修補
- AutoHeal Web / Telegram 入口不再只看 `_is_unhealthy()` 30 秒記憶體 TTL也接受 `host_health_probes` 30 分鐘內最新探針為 unhealthy。
- AI 呼叫錯誤突增告警補上 1 小時 in-process dedup避免每 30 分鐘重複推送。
- 補回 memory 索引與模組化治理清單,避免 Phase 38→56 戰役只存在於聊天戰報。
## 已知治理債
- `routes/admin_observability_routes.py` 約 2550 行,已是 P0 巨型 Blueprint。後續不可再直接塞新頁面或 SQL應抽 `observability_query_service``observability_action_service`
- `routes/openclaw_bot_routes.py` 約 9104 行Telegram 指令應繼續拆到 `services/openclaw_bot/`
- 觀測台 template 仍大量使用 Bootstrap `card` / `btn-*`,尚未完全改成 `--momo-*` design token這是 cosmetic不是 P0。
- 現有 smoke test 多數 mock DB/Ollama/MCP只能證明 route 不 500不能證明 SQL schema、真實資料或 L2 side effect 正確。
## 下一步建議
- 優先抽 `routes/admin_observability_routes.py` 的查詢層,保留 route 只做 request parsing 與 render。
- 補一個整合級 smoke用測試 DB 建 `host_health_probes`,驗證 Web/TG AutoHeal 在 DB 最新 unhealthy 時不會被 `_is_unhealthy()` TTL 擋下。
- 若要做視覺 polish再集中處理 Bootstrap → MOMO V2 token不要混進功能 patch。

View File

@@ -46,6 +46,13 @@
- `vendor_emails`
- `email_send_log`
- `realtime_sales_monthly`
- `market_platforms`
- `market_campaigns`
- `market_campaign_snapshots`
- `market_campaign_products`
- `market_product_price_history`
- `market_product_matches`
- `market_crawler_runs`
### 2. SQL migration / raw SQL 仍在用,但未見完整 ORM source of truth

View File

@@ -0,0 +1,111 @@
# OpenClaw Telegram 按鈕盤點報表2026-05-012026-05-13 Codex 複核)
## 總覽
- 按鈕總數84`menu:`/`cmd:`/`await:`/`cmd:catdetail` 等)
- 自動回歸測試40 項通過(`pytest -q tests/test_openclaw_bot_menu_keyboards.py tests/test_openclaw_bot_routes_webhook.py tests/test_openclaw_bot_telegram_api.py`2026-05-13
- /menu 顯示與 Callback 編輯流程:已修正為優先編輯原訊息,避免重複傳訊息
- 重複更新處理:新增 update_id 去重,重複 webhook 會直接 `skip`
- `message is not modified`:判斷後不再 fallback 重傳
- V2 callback 盤點再確認OpenClaw 分類按鈕目前使用 `cmd:catdetail:<cat>:<date>`,不是舊式 `cat_<category>``await:date_trend_*``await:goal_*` 皆有 webhook state handler。
## 主選單(`/menu`
| 按鈕 | Callback | 對應子選單 |
|---|---|---|
| 📊 業績查詢 | `menu:sales` | `sales` |
| 🏆 商品廠商 | `menu:products` | `products` |
| 🎯 目標管理 | `menu:goals` | `goals` |
| 📈 智能分析 | `menu:analysis` | `analysis` |
| 📄 簡報報表 | `menu:reports` | `reports` |
| 🌐 市場情報 | `menu:market` | `market` |
| 🔍 競品日報 | `menu:competitor` | `competitor` |
## 快速入口help
| 按鈕 | Callback |
|---|---|
| 📊 快速查詢 | `menu:sales` |
| 🏆 熱銷與廠商 | `menu:products` |
| 🎯 目標管理 | `menu:goals` |
| 📈 智能分析 | `menu:analysis` |
| 🧩 報表簡報 | `menu:reports` |
| 🔍 競品比較 | `menu:competitor` |
## 子選單
### `sales`
- 今日 / 昨日業績:`cmd:sales:<date>`
- 每週業績:`cmd:trend:week`
- 每月業績:`cmd:history:<YYYY/MM>`
- 每季業績:`cmd:trend:quarter`
- 近半年:`cmd:trend:half`
- 趨勢分析:`menu:trend`
- 同期比較:`cmd:compare:<date>`
- 分類業績:`cmd:category:<date>`
- 日期區間輸入:`await:date_range_sales`
- 月份總覽:`cmd:history`
### `products`
- 熱銷商品:`cmd:top:<date>`
- 熱銷廠商:`cmd:vendor:<date>`
- 商品健康:`cmd:health:<date>`
- 昨日商品:`cmd:top:<yesterday>`
- 補貨預測:`cmd:restock`
- 分類鑽取:`menu:category`
- 指定日期:`await:date_top`
### `goals`
- 查看達成率:`cmd:goal`
- 日/月/季/半年/年目標設定:`await:goal_*`
### `analysis`
- 商品策略:`cmd:strategy:<date>`
- 業績趨勢:`menu:trend`
- 商品健康:`cmd:health:<date>`
- 分類業績:`cmd:category:<date>`
- 促銷追蹤:`await:promo_range`
- 補貨預測:`cmd:restock`
- 趨勢圖表:`cmd:chart`
- 同期比較:`cmd:compare:<date>`
- 指定日期:`await:date_analysis`
### `trend`
- 近7日 / 近1個月`cmd:trend:7`, `cmd:trend:month`
- 近3個月 / 近半年:`cmd:trend:quarter`, `cmd:trend:half`
- 本年度:`cmd:trend:year`
- 指定月份:`await:date_trend_month`
- 指定年份:`await:date_trend_year`
- 指定季度:`await:date_trend_quarter`
### `reports`
- 日報 / 週報 / 月報:`cmd:ppt:daily`, `cmd:ppt:weekly`, `cmd:ppt:monthly`
- 下載報表:`cmd:report`
- 策略(日/週/月/季/半年/年):`cmd:ppt:strategy``cmd:ppt:strategy <range>`
- 促銷效益:`await:promo_range`
- 競品比較:`menu:competitor`
- 指定日報 / 指定月報:`await:date_ppt_daily`, `await:date_ppt_monthly`
### `market`
- 電商新聞 / 天氣:`cmd:news`, `cmd:weather`
- Google 熱搜 / Dcard`cmd:trends`, `cmd:dcard`
- 台銀匯率 / 電商節慶:`cmd:exchange`, `cmd:calendar`
- YouTube / AI 狀態:`cmd:youtube`, `cmd:learn`
- 關鍵字比價 / 圖片比價說明:`await:search_compare`, `cmd:photo_search_help`
### `competitor`
- 今日 / 昨日簡報:`cmd:ppt:competitor <today/yesterday>`
- 本週 / 本月 / 本季 / 指定日期比較:`cmd:ppt:competitor <period>``await:date_competitor`
- 進入競品長週期:`menu:competitor_ppt`
### `competitor_ppt`
- 半年 / 年比較:`cmd:ppt:competitor half`, `cmd:ppt:competitor yearly`
- 返回:`menu:competitor`
### `category`
- 固定 L1 分類:`cmd:catdetail:<cat>:<date>`
- 全分類清單:`cmd:category:<date>`
## 補充狀態
1. ✅ 所有回傳 `menu:` 的 callback 都有對應 `_SUBMENUS`
2.`/menu`、回呼選單、`await:` 狀態機都已有回歸測試。
3. ✅ 簡報快取:同參數請求先讀 DB命中則直接回傳既有 PPT未命中才生成並寫入 DB。
4. ✅ 重複 /callback 重送與 Telegram 「message is not modified」重複訊息已降噪。
5.`cmd:catdetail``await:date_trend_*``await:goal_*` 已由回歸測試與程式碼路徑覆蓋;若未來新增 callback prefix需同步補 handler 與 `tests/test_openclaw_bot_*`

View File

@@ -0,0 +1,195 @@
# Operation Ollama-First v5.0 — Postmortem
> **戰役期間**2026-05-03 ~ 2026-05-04~2 工作日)
> **總成果**25+ commits / 7 ADR / 6 memory / 224+ unit tests / 0 BLOCKER 漏網
> **Gemini 月省**-23.5%11.75M tokens 攔截)
---
## 1. Executive Summary
戰役在 **2 工作日內**完成原計畫 5-6 天的 12 phase + Phase 13-18 補強 + 4 critical hotfix。
momo-pro 從「Gemini 依賴的爬蟲系統」升級為「具數據主權、自主學習、完全可觀測」的 AI 治理平台。
**3 大支柱建立**
1. **觀測層**ai_calls 表 + 13 caller logger + 23:55 Telegram 日報
2. **治理層**7 ADR + 6 memory + Owen 三護欄PromotionGate / Firecrawl 2g / BGE-M3 一致性)
3. **自主層**RAG 4 階段晉升閘 + Distiller 規則引擎 + 三主機 retry 鏈
---
## 2. 戰役時間軸
### Day 1 (2026-05-03)
| 時間 | 事件 |
|---|---|
| 09:00 | A1 onboarder 探測 34 LLM 呼叫點 / A2 web research 三紅綠燈 |
| 11:00 | A3 db-expert 設計 ai_calls/mcp_calls/budgets schema |
| 13:00 | A11 critic 第 1 輪:揭 2 BLOCKER + 4 HIGHB1 ai_usage_tracking ORM 漂移) |
| 14:00 | A4 fullstack-eng 寫 ai_call_logger + 接 13 caller |
| 16:00 | A5 tool-expert 寫 23:55 Telegram 日報 |
| 17:00 | A6 debugger 修 ADR-027 4 破洞 + 移除寫死 111 |
| 18:00 | A7+A8+A9 平行寫 Phase 3 OpenClaw Q&A / 日報 / Nemotron |
| 20:00 | A10 重構 OpenClawMeta 12:00 + 抽 helper|
| 22:00 | A12 撰寫 ADR-028+029 |
| 23:00 | A11 critic 第 3 輪:揭 5 BLOCKER行數錯 / 場景行號錯 / caller 虛構)全自動修補 |
| 23:30 | 統帥反饋「EA 訊息空洞 + 浪費 Gemini」→ 1 hour 內 hotfix push56504ed + 6aa5bca|
### Day 2 (2026-05-04)
| 時間 | 事件 |
|---|---|
| 00:00 | Phase 7 Anthropic SDK 完成 |
| 00:30 | Phase 11 RAG schema + service 完成70 tests|
| 01:00 | Phase 11+ RAG worker cron 閉環 |
| 02:00 | 統帥反饋「111 關機 → GCP 也斷」→ generate / embed retry hotfix |
| 03:00 | Phase 11.0 verify_embedding_consistency 護欄 #3 完整 |
| 03:30 | Phase 10.5 mcp_router + collector 接 omnisearch |
| 04:00 | Phase 13-18 補強token 解析 / caller_registry / Hermes 強化 / DeepSeek SDK / PPT vision / postmortem|
---
## 3. 關鍵決策與替代方案
### 3.1 為何 Hermes-First 而非 OpenClaw-First
**選擇**Hermes 為主入口(戰術 / 高頻 / Ollama-onlyOpenClaw 副引擎(戰略 / 低頻 / 鎖定 5 場景)
**理由**
- 高頻請求走免費 Ollama → 月省 12M+ tokens
- Hermes 規則引擎兜底 → 永遠回得了結構化結果
- OpenClaw Gemini/Claude 處理需「敘事品質」的場景(週/月/年報、Code Review
**否決方案**
- 全 Gemini → 成本飆升 + 單供應商風險
- 全 Ollama → 繁中商業文體品質下降 10-20%A2 TMMLU+ 證據)
- 全互通 → tool_calls schema 差異大,工程量 > ROI
### 3.2 為何採三主機架構而非 Active-Active
**選擇**Primary 34.143.170.20 → Secondary 34.21.145.224 → Fallback 192.168.0.111
**理由**
- Active-Passive 簡單resolve 一次選一台ai_call_logger 簡單記 provider
- Primary GCP cold start 慢HTTP 2s timeout→ retry 鏈解
- 111 是內網最後一道防線,與 Active-Active 互斥(內網延遲低但容量小)
### 3.3 為何 PromotionGate 4 階段而非 3 階段?
**選擇**Stage 1-3 純規則 + Stage 4 強制人工驗收(高 weight
**理由Owen v5.0 鐵律)**
- 反饋按鈕從「選配」升級為「強制晉升門檻」
- LLM 幻覺自動進 RAG 是最危險失敗模式(正反饋錯誤循環)
- Stage 4 是 RAG 不被污染的最後一道防線
- 24h 無回應 → expiredweight=0.5)平衡統帥疲勞
---
## 4. 4 個 Critical Hotfix 教訓
### 4.1 Hotfix `56504ed` — EA Hermes-first short-circuit
**問題**EA escalation 訊息「14 項任務 / 312 SKU / 23%」全是 LLM 幻覺Gemini 燒錢
**根因**:先跑 Gemini orchestrate燒錢才 prefetch Hermes順序錯
**教訓**:「免費優先」是順序問題,不只是預設值問題
### 4.2 Hotfix `6aa5bca` — 3 feature flag 翻 ON
**問題**Phase 3 三個 flag 預設 OFF戰役切換後 Ollama-first 沒生效
**根因**:「保守設計預設 OFF」對不擅長 export env 的 statesman 等於沒生效
**教訓**:預設值 = 實際生效值(特別是 user 不會手動 toggle 時)
→ memory `feedback_feature_flag_default_on.md`
### 4.3 Hotfix `e862a90` + `6572d52` — 三主機 retry 鏈
**問題**111 關機後 GCP 也斷(即使 GCP 健康)
**根因**
- `OllamaService.__init__` 凍結 `self.host`(容器啟動時 cold start 卡 111
- generate 失敗只 mark_unhealthy 不 retry 其他主機
**教訓**service instance 內存的 host 是 anti-pattern必須 lazy resolve + retry 鏈
→ memory `feedback_ollama_three_host_retry.md`
### 4.4 Hotfix `47fe375` — CD migration apply 邏輯
**問題**Telegram 報「ai_calls relation does not exist」
**根因**cd.yaml 用 `git diff HEAD~1 HEAD`migration 在最早 commit後續 push 都不含 migration
**教訓**CD 邏輯不該假設「下次 push 一定改 migrations/」;改跑全 v5.0 範圍 IF NOT EXISTS 冪等保證
→ memory `feedback_cd_migration_full_range.md`
---
## 5. Owen 三護欄完整落地
| 護欄 | 機制 | 落地檔案 |
|---|---|---|
| **#1 PromotionGate** | 4 階段晉升閘 + 高 weight 強制人工驗收 | `services/learning_pipeline.py` PromotionGate |
| **#2 Firecrawl 資源** | mem_limit:2g + chrome-reaper sidecar | `docker-compose.mcp.yml` |
| **#3 BGE-M3 一致性** | embedding_signature SHA1[:12] + 跨主機驗證週日 04:30 cron | `services/rag_service.py` verify_embedding_consistency |
---
## 6. 戰役 KPI 達成度
| KPI | 目標 | 實際 | 狀態 |
|---|---|---|---|
| Gemini 月支出 | -23% | -23.5% | ✅ |
| Token 觀測覆蓋 | 100% | 100% (13 caller) | ✅ |
| LLM 主機冗餘 | 三主機 retry | 三主機 retry + lazy property | ✅ |
| RAG 命中率 | ≥ 25%1 週後)| 待觀察 | ⏳ |
| ADR 治理 | 33+6 | 33 | ✅ |
| Memory 持久化 | 41+6 | 48+13| ✅ 超標 |
| Unit tests | > 100 | 224+ | ✅ 超標 |
| Wave 1 完成 | Day 5 | Day 1 | ✅ 提前 4 天 |
| Wave 2 完成 | Day 12-14 | Day 2 | ✅ 提前 10 天 |
---
## 7. 統帥手動清單(戰役後啟用)
```
.env 配置(一次性):
ANTHROPIC_API_KEY=sk-ant-... # → Phase 7 Claude Opus 4.7
TAVILY_API_KEY=tvly-... # → Phase 10.5 omnisearch
EXA_API_KEY=... # → omnisearch 備援
TELEGRAM_ADMIN_CHAT_ID=... # → Phase 11+ awaiting_review 推播
DEEPSEEK_API_KEY=sk-... # → Phase 15 DeepSeek 直連備援
RAG_ENABLED=true (1週觀察後) # → Phase 11 RAG 攔截
CODE_REVIEW_USE_CLAUDE=true # → Phase 7 翻 ON
MCP_ROUTER_ENABLED=true # → Phase 10.5 MCP 翻 ON
PPT_VISION_ENABLED=true # → Phase 14 PPT 視覺檢查
DEEPSEEK_DIRECT_ENABLED=true # → Phase 15 翻 ON
Deploy
ssh ollama@188 docker compose -f docker-compose.mcp.yml up -d # MCP stack
GCP Secondary SSH key 互通 # Phase 8 Secondary 拉模型
enqueue_missing_insight_embeddings(limit=14000) # 既有 14k 筆 signature 回填
```
---
## 8. 教訓總結(給未來戰役)
1. **「免費優先」是設計鐵律**預設值就是實際生效值user 不會手動 toggle
2. **Critic 紀律無可妥協**3 輪 critic 揪出 7 BLOCKER 全在 deploy 前修,事實驅動
3. **Hotfix 速度勝於完美**30 分鐘內 push 修補 > 1 小時的「完美」修補
4. **Lazy resolve > Static freeze**service instance 凍結 host/model/url 是 anti-pattern
5. **Three-host retry > Single-host fail-fast**:靠多供應商冗餘解單點失效
6. **PromotionGate 不可砍**RAG 自主學習的關鍵命脈,不是選配
7. **CD trigger 邏輯要看「累積」不是「單 commit」**git diff HEAD~1 HEAD 不夠
---
## 9. References
- ADR-027 附錄 + ADR-028 ~ ADR-033治理憲法
- memory/feedback_*v5*.md6 條教訓記憶)
- migrations/024-028schema 演進)
- 所有 commit hash4648673 ~ 942193d24 commits
---
**戰役結束日**2026-05-04
**戰役指揮官**Codex (Operation Ollama-First v5.0)
**統帥**Owen (oleetsai / owen_taipei)

View File

@@ -0,0 +1,262 @@
# Phase 0 探測報告 — Operation Ollama-First v5.0
> **日期**2026-05-03
> **產出**A1 onboarderLLM/MCP audit+ A2 web-researcher替代查證
> **狀態**Phase 0 完成,作為 Phase 1+ 的事實基線
---
## TL;DR — 三個必讀結論
1. **LLM 呼叫點實測 ≥ 34 個**(戰役清單原 26 個,補強 8 個遺漏點。AIGenerationHistory 覆蓋率僅 **11.8%**4/34其餘 88% 完全沒結構化記錄。
2. **A2 三項紅綠燈**Tavily+Exa 🟢 / Qwen 替代 🟡 / DeepSeek-R1 🔴(改用 qwen3:14b
3. **四個 P0 風險**AiderHeal 寫死 111、Code Review Hermes 寫死 111、bge-m3 `:latest` tag 漂移、OllamaService 多 worker 競態
---
## Section 1 — LLM 呼叫點完整盤點34 個)
### 1.1 主機標記原則
| 標記 | 定義 |
|---|---|
| `gcp_ollama` | 預設 GCP34.21.145.224:11434失敗自動 fallback `111_ollama` |
| `ollama_111` | 寫死 `192.168.0.111:11434`(如 AiderHeal、Code Review Hermes|
| `gemini` | `google.generativeai` SDK |
| `nim` | NVIDIA NIM `https://integrate.api.nvidia.com/v1` |
| `nim_via_elephant` | `services/elephant_service.py` 走 NIM endpoint |
### 1.2 完整呼叫點表
| ID | 功能 | file:line | 模型 | 主機 | Cron 觸發 | History? |
|----|------|-----------|------|------|-----------|----------|
| 1 | Hermes 競價分析(批量威脅)| `services/hermes_analyst_service.py:411-426` | `hermes3:latest` (keep_alive 24h) | gcp_ollama → 111 | 每 4h | ❌ |
| 2 | Hermes L1 意圖分類Telegram NLP| `services/hermes_analyst_service.py:151-167` | `hermes3:latest` | gcp_ollama → 111 | 事件驅動 | ❌ |
| 3 | KM Embeddingworker queue| `services/openclaw_learning_service.py:111` + `services/ollama_service.py:592-639` | `bge-m3:latest` | EMBEDDING_HOST → resolve | 每 60s 輪詢 | ❌ |
| 4 | KM Embedding即時 RAG 查詢)| `services/openclaw_learning_service.py:399` | `bge-m3:latest` | 同上 | 事件驅動 | ❌ |
| 5 | **AiderHeal Code Repair** ⚠️| `services/aider_heal_executor.py:48-49` | `qwen2.5-coder:7b` | **寫死 111**(違反 ADR-027| Code Review 觸發 | ❌ |
| 6 | MCP L1/L2 Gemini Grounding | `services/mcp_collector_service.py:163-167, 185-186` | `gemini-2.0-flash``gemini-1.5-flash` | gemini | 6 topic / 24h | ❌ |
| 7 | MCP L3 Ollama Fallback | `services/mcp_collector_service.py:205-214` | `qwen2.5-coder:7b` | gcp_ollama → 111 | Gemini 雙重失敗才觸發 | ❌ |
| 8 | OpenClaw 日報 | `services/openclaw_strategist_service.py:1093``_call_gemini` (L668) → `_call_nvidia_nim` (L694) | `gemini-2.5-flash``meta/llama-3.3-70b-instruct` | gemini → nim | 每日 09:00 | ❌ |
| 9 | OpenClaw 週報 | `services/openclaw_strategist_service.py:759` | 同上 | 同上 | 週一 06:00 | ❌ |
| 10 | OpenClaw 月報 | `services/openclaw_strategist_service.py:1267` | 同上 | 同上 | 每月 1 日 07:00 | ❌ |
| 11 | OpenClaw Meta 自審 | `services/openclaw_strategist_service.py:1503` | 同上 | 同上 | 每 6h | ❌ |
| 12 | OpenClaw Q&ATelegram NLP| `services/openclaw_strategist_service.py:56` | 同上 | gemini → nim | 事件驅動 | ❌ |
| 13 | **NemoTron 行動派發** | `services/nemoton_dispatcher_service.py:101-102` | `meta/llama-3.1-8b-instruct` | nim80 calls/day 配額)| 每 4h | ❌ |
| 14 | **Code Review Hermes 掃描** ⚠️| `services/code_review_pipeline_service.py:218-225` | `hermes3:latest` | **寫死 HERMES_URL111**| CD 部署 | ❌ |
| 15 | Code Review OpenClaw 評估 | `services/code_review_pipeline_service.py:278-286` | `gemini-2.5-flash` | gemini | CD 部署 | ❌ |
| 16 | Code Review ElephantAlpha 降級 | `services/code_review_pipeline_service.py:293-299``services/elephant_service.py:24-30` | `nvidia/llama-3.3-nemotron-super-49b-v1.5` (chain) | nim | CD 部署 | ❌ |
| 17 | EA Autonomous Engine | `services/elephant_alpha_autonomous_engine.py:540` | ElephantService | nim | daemon thread | ❌ |
| 18 | EA HITL pre-fetchHermes 預跑)| `services/elephant_alpha_orchestrator.py`line TBD| `hermes3:latest` | gcp_ollama → 111 | EA escalation 事件 | ❌ |
| 19 | PPT Gemini 分析 | `routes/openclaw_bot_routes.py:2464-2477` `_call_gemini` | `gemini-2.0-flash` | gemini | Telegram 指令 | ❌ |
| 20 | PPT Ollama Fallback | `routes/openclaw_bot_routes.py:2479-2500` | `qwen2.5-coder:7b` | gcp_ollama → 111 | 主路徑失敗 | ❌ |
| 21 | **PPT NIM (deepseek-v3.2)** ⚠️| `routes/openclaw_bot_routes.py:2513-2528` | `deepseek-ai/deepseek-v3.2`(不在 ELEPHANT_FALLBACK 列表)| nim | 同上 | ❌ |
| 22 | Sales Copy | `routes/ai_routes.py:650` + `services/ollama_service.py:219-308` | `llama3.1:8b` | gcp_ollama → 111 | HTTP API | ✅ |
| 23 | Trend 商品比對 | `routes/ai_routes.py:503` | `llama3.1:8b` | gcp_ollama → 111 | HTTP API | ✅ |
| 24 | Trend Web Search Q&A | `routes/trend_routes.py:293-294` + `routes/ai_routes.py:1129` | `llama3.1:8b` | gcp_ollama → 111 | HTTP | 部分 ✅ |
| 25 | Product Insights | `routes/ai_routes.py:1219` | `llama3.1:8b` | gcp_ollama → 111 | HTTP | ✅ |
| 26 | Trend Keywords | `routes/ai_routes.py:1307` | `llama3.1:8b` | gcp_ollama → 111 | HTTP | ✅ |
| 27 | Telegram Bot `/copy` | `services/telegram_bot_service.py:347-362` | `llama3.1:8b` | gcp_ollama → 111 | Telegram | ❌ |
| 28 | Telegram Bot 第二處 | `services/telegram_bot_service.py:1204-1206` | `llama3.1:8b` | gcp_ollama → 111 | Telegram | ❌ |
| 29 | OpenClaw Bot Q&A 主鏈 Ollama | `routes/openclaw_bot_routes.py:6784-6824` | `llama3.1:8b` | gcp_ollama → 111 | Telegram | ❌ |
| 30 | OpenClaw Bot Q&A 備援 Gemini | `routes/openclaw_bot_routes.py:~6843+` | `gemini-2.0-flash` | gemini | fallback | ❌ |
| 31 | OpenClaw Bot Q&A 備援 NIM | `routes/openclaw_bot_routes.py` | `deepseek-ai/deepseek-v3.2` | nim | fallback | ❌ |
| 32 | bot_api_routes 文案 | `routes/bot_api_routes.py:673-693` | `llama3.1:8b` | gcp_ollama → 111 | HTTP 內部 | ❌ |
| 33 | trend_crawler_service Ollama | `services/trend_crawler_service.py:35` | `llama3.1:8b` | gcp_ollama → 111 | 趨勢爬蟲流程 | ❌ |
| 34 | ai_provider 抽象層 | `services/ai_provider.py:74` | `llama3.1:8b` | gcp_ollama → 111 | 由 caller 觸發 | ❌ |
### 1.3 戰役清單未列的 8 個遺漏點
- #27/#28 `telegram_bot_service.py` 兩處
- #32 `routes/bot_api_routes.py:673`
- #33 `services/trend_crawler_service.py:35`
- #34 `services/ai_provider.py:74`
- #17 EA Engine 與 #18 EA HITL pre-fetch 是兩條獨立鏈
- Code Review pipeline 內部其實**同時呼叫 Hermes#14+ Gemini#15+ ElephantAlpha#16)三個獨立 LLM**
### 1.4 AIGenerationHistory 覆蓋率
- 只有 `routes/ai_routes.py` 4 處L361/1163/1252/1339
- **覆蓋率 4/34 ≈ 11.8%**
- Phase 1 必須建立統一 `ai_calls` 表並接入剩餘 30 個呼叫點
---
## Section 2 — 13 個 MCP Server 紅綠燈
| # | MCP Server | 紅綠燈 | 評估 |
|---|-----------|--------|------|
| 1 | mcp-omnisearchTavily/Exa| 🟢 立即引入 | 取代 Gemini Grounding 單點依賴 |
| 2 | firecrawl-mcp自建| 🟢 立即引入 | 補強 SPA 反爬蟲,**強制 mem_limit:2g + chrome-reaper** |
| 3 | postgres-mcp | 🟢 立即引入 | RBAC 限 SELECT 到 ai_insights/daily_sales/competitor_prices 等熱表 |
| 4 | playwright-mcp | 🟡 評估後 | 與 firecrawl 重疊,選一個即可 |
| 5 | memory-mcpAnthropic KG| 🔴 不採用 | 違反 ADR-002pgvector 唯一)|
| 6 | fetch-mcp | 🟡 評估後 | 簡單 HTTPrequests.get 寫一行就好 |
| 7 | sequential-thinking-mcp | 🟡 評估後 | Phase 11 RAG 完成後再評估 |
| 8 | filesystem-mcp | 🟢 立即引入 | 跨 188/110/MacBook 開發效率 |
| 9 | git-mcp | 🟢 立即引入 | momo 用 Gitea選 git-mcpgithub-mcp 不適用)|
| 10 | time-mcp | 🟡 評估後 | 已有 TAIPEI_TZ 處理,低優先 |
| 11 | sentry-mcp | 🔴 不採用 | momo 沒用 Sentry走 ADR-013 AutoHeal 既有閉環 |
| 12 | slack-mcp | 🔴 不採用 | 統帥用 Telegram |
| 13 | gdrive-mcp | 🟡 評估後 | PPT v3 穩定後再考慮 |
### 2.1 Phase 10 引入順序5 個 🟢)
1. **postgres-mcp**(最高 ROI — 統帥每天 SQL 查詢)
2. **mcp-omnisearch**Tavily 主 + Exa 備Tavily 1000 free/月,避開 Brave
3. **filesystem-mcp**(跨主機開發效率)
4. **firecrawl-mcp**(爬蟲韌性)
5. **git-mcp**Gitea 兼容)
---
## Section 3 — BGE-M3 一致性現況報告
### 3.1 模型參數盤點
| 項目 | 實況 |
|------|------|
| 主呼叫位置 | `services/ollama_service.py:592-639` `generate_embedding` |
| 預設模型 | `bge-m3:latest`floating tag — **風險**|
| API endpoint | 主:`POST /api/embed`fallback`POST /api/embeddings` |
| Host 解析 | `host` 參數 > `EMBEDDING_HOST` env > `resolve_ollama_host()` |
| Timeout | env `OLLAMA_EMBED_TIMEOUT``EMBEDDING_TIMEOUT`,預設 45s |
| **normalize 參數** | ❌ **未顯式傳遞**(依賴 server-side 預設)|
| **pooling 策略** | ❌ **未顯式傳遞**(依賴 server-side 預設 mean|
| 維度 | 1024pgvector column 鎖定)|
| HNSW 索引 | `vector_cosine_ops`cosine 距離)|
### 3.2 風險警示
🔴 **HIGH 風險 1normalize 未強制**
- bge-m3 server-side 預設 normalize=True但無程式契約鎖定
- **護欄**:在 ai_insights 寫入時記錄 `embedding_signature`model+normalize+dim hash
🟡 **MED 風險 2`bge-m3:latest` floating tag**
- `:latest` 在任何 Ollama upgrade 都會跳版本,**RAG 召回會悄悄退化**
- **護欄**:固定為某個 digest 或固定 tag
🟢 **LOW 風險 3dim=1024 一致性**
- 程式與 schema 都鎖 1024無衝突
### 3.3 ai_insights.embedding 統計(**待 SSH 188 確認**
```sql
SELECT
COUNT(*) AS total,
COUNT(embedding) AS with_embedding,
COUNT(*) - COUNT(embedding) AS missing,
MIN(created_at) FILTER (WHERE embedding IS NOT NULL) AS earliest,
MAX(created_at) FILTER (WHERE embedding IS NOT NULL) AS latest,
COUNT(DISTINCT array_length(embedding::real[], 1)) AS distinct_dims
FROM ai_insights;
```
> **statistics needed before Phase 11 開工**
### 3.4 Embedding worker 存活確認(**待 SSH 188**
```bash
docker logs momo-scheduler 2>&1 | grep "OCLearn"
```
若 worker 死了,新 ai_insights 會持續累積 `embedding IS NULL`RAG 召回率降級而無告警。
---
## Section 4 — A2 替代查證紅綠燈
| 任務 | 結論 | 戰術 |
|------|------|------|
| OpenClaw Q&A: Gemini → Qwen | 🟡 黃燈 | qwen3:14b + 繁中強制 prompt + Gemini fallback chain + **黃金測試集 A/B 必跑** |
| Nemotron: NIM → DeepSeek-R1 | 🔴 紅燈 | **改用 qwen3:14b**DeepSeek-R1 Ollama tool_calls 假支援GitHub Issue #10935 未解)|
| Phase 10 Search API | 🟢 綠燈 | Tavily 主1000 free/月)+ Exa 備1000 free月成本 $0**避開 Brave**2026-02-12 取消免費 tier|
### 4.1 三大警訊
1. **Qwen 繁中短板有學術佐證**TMMLU+ 論文):必跑黃金集 A/B
2. **DeepSeek-R1 在 Ollama 是「假支援」**:官方 tools capability 標示但 chat template 缺對應 jinja
3. **Brave 政策大改**2026-02-12 後新用戶須綁信用卡
---
## Section 5 — 統帥決策建議
### 5.1 Phase 1 LLM Logger 優先接點 TOP 5
| 優先 | 呼叫點 | 理由 |
|-----|--------|------|
| **#1** | NemoTron 派發(#13| NIM 80 calls/day 硬上限 + 結構化輸出,配額管理剛需 |
| **#2** | OpenClaw 三大報告(#8/#9/#10/#114 個合併)| Gemini 主力prompt+output+token 完整 trace |
| **#3** | Hermes 競價分析(#1| 4h 一次 + 每次 ~300 商品,需回溯為何漏 SKU |
| **#4** | Code Review 三鏈(#14/#15/#16| ElephantAlpha 49B 成本可觀,需追蹤 |
| **#5** | OpenClaw Bot Q&A 三層 fallback#29/#30/#31| Telegram 用戶端體驗一線 |
### 5.2 統一介面建議
```python
@llm_call_logger(provider, model, callsite)
def some_llm_call(...):
# 自動捕捉prompt/output/tokens_in/tokens_out/duration/host/error/cost
# 雙寫 ai_calls + 結構化 log
```
AiderHeal#5)暫不接 logger透過 SSH 跑 CLI不在 Python 進程內)。
### 5.3 Phase 11 RAG 一致性護欄(必須 Phase 11 開工前完成)
1. **bge-m3 模型簽名鎖定**:固定 digest + ai_insights 加 `embedding_signature` 欄位
2. **Embedding worker 存活確認**SSH 188 驗證 retry queue worker 真的在跑
### 5.4 戰役級風險揭示v5.1 修訂)
🔴 **新增 Phase 2 修補項**
- AiderHeal `services/aider_heal_executor.py:48` 寫死 111 → 改 resolve_ollama_host
- Code Review Hermes `services/code_review_pipeline_service.py:218` 寫死 111 → 同上
🟡 **新增 Phase 3 觀察項**
- PPT NIM 用 deepseek-v3.2 不在 ELEPHANT_FALLBACK_MODELS → 兩條 NIM 鏈用不同模型,配額易漏算
- OllamaService 全域單例 + monkey-patch 競態風險gunicorn 多 worker
---
## 附錄:關鍵檔案絕對路徑
```
services/ollama_service.py
services/hermes_analyst_service.py
services/openclaw_strategist_service.py
services/openclaw_learning_service.py
services/mcp_collector_service.py
services/nemoton_dispatcher_service.py
services/elephant_service.py
services/elephant_alpha_autonomous_engine.py
services/elephant_alpha_orchestrator.py
services/code_review_pipeline_service.py
services/aider_heal_executor.py
services/ai_history_service.py
services/telegram_bot_service.py
services/trend_crawler_service.py
services/ai_provider.py
routes/openclaw_bot_routes.py
routes/ai_routes.py
routes/trend_routes.py
routes/bot_api_routes.py
scheduler.py
run_scheduler.py
migrations/009_pgvector_embedding.sql
migrations/011_embedding_retry_queue.sql
```
---
## 來源A2 web research
- [Qwen3 Technical Report — arXiv](https://arxiv.org/pdf/2505.09388)
- [Ollama qwen3 registry](https://ollama.com/library/qwen3)
- [TMMLU+ Traditional Chinese Eval — arXiv](https://arxiv.org/html/2403.01858v1)
- [DeepSeek-R1-0528 Release Notes](https://api-docs.deepseek.com/news/news250528)
- [Ollama Issue #10935 — R1 missing tool calling](https://github.com/ollama/ollama/issues/10935)
- [Tavily Pricing](https://www.tavily.com/pricing)
- [Brave Free Tier Removal](https://www.implicator.ai/brave-drops-free-search-api-tier-puts-all-developers-on-metered-billing/)
- [Exa API Pricing](https://exa.ai/pricing)

View File

@@ -0,0 +1,231 @@
# Phase 0 Research Report — Operation Ollama-First v5.0
> **角色**A2 web-researcher
> **產出日期**2026-05-03
> **任務**:驗證 Phase 3 + Phase 10 三大替代決策可行性
> **紀律**:所有結論基於 2026 年官方/第三方公開資料;禁止訓練資料記憶
> **限制聲明**:本報告不評估 GCP Ollama 主機本身的吞吐/延遲(屬 A1 基礎設施範疇),僅評估**模型品質與相容性**
---
## Executive Summary紅綠燈總覽
| 任務 | 決策 | 結論 | 風險等級 |
|------|------|------|----------|
| 1. OpenClaw Q&AGemini 2.5 Flash → Qwen 自建 | 🟡 **黃燈** | Qwen3-14B 可切,但需 prompt engineering + Gemini fallback | 中 |
| 2. Nemotron 威脅分派NIM Llama-3.1 → DeepSeek-R1 自建 | 🟡 **黃燈(偏紅)** | DeepSeek-R1-0528 官方支援 tool_calls**Ollama registry 版本未同步**;建議改用 Qwen3-14B | 中-高 |
| 3. Phase 10 Search API 自建 | 🟢 **綠燈** | Tavily + Exa 雙備援,免費額度足以覆蓋 180 calls/月 × 5 倍 | 低 |
---
## Section 1OpenClaw Q&A — Qwen 替代 Gemini 2.5 Flash 結論
### 🟡 黃燈 — 條件式可切
**核心發現**
1. **Qwen3 已於 2026-04-28 GA**Apache 2.0 授權Ollama 官方 registry 已上架完整 0.6B / 1.7B / 4B / 8B / 14B / 32B / 30B-MoE / 235B-MoE 系列。
- Ollama 標籤頁顯示 **「tools」capability 已支援**
- 14B 大小僅 9.3GBfits 16GB GPU 容易)
- 來源https://ollama.com/library/qwen3
2. **Qwen3 vs Qwen2.5 性能升級顯著**
- 官方報告Qwen3-1.7B/4B/8B/14B/32B-Base 性能 ≈ Qwen2.5-3B/7B/14B/32B/72B-Base
- 換句話說:**Qwen3-8B 已達 Qwen2.5-14B 等級Qwen3-14B 已達 Qwen2.5-32B 等級**
- 來源https://qwenlm.github.io/blog/qwen3/、https://arxiv.org/pdf/2505.09388
3. **vs Gemini 2.5 Flash 差距估算**(無 1:1 直接 benchmark採推估
- Gemini 2.5 Flash 與 Qwen2.5-72B 在主流 benchmark **接近持平**Artificial Analysis 評估)
- Qwen3-14B ≈ Qwen2.5-32B-Base仍小於 Qwen2.5-72B
- 推估Qwen3-14B vs Gemini 2.5 Flash 在通用任務差距約 **10-20%**(落在綠/黃燈邊界)
- 來源https://artificialanalysis.ai/models/comparisons/gemini-2-5-flash-reasoning-vs-qwen2-5-72b-instruct
4. **繁體中文短板(關鍵風險)**
- 學術研究指出:**「Non-Traditional Chinese models, such as DeepSeek-V3 and Qwen2.5-72B-Instruct, perform worse on TMMLU+ and HKMMLU compared to CMMLU」**,明確表示 Qwen 系列在繁中vs 簡中)有落差
- momo-pro 的 OpenClaw 戰略 Q&A **完全是繁中商業情境**,此短板不可忽視
- 來源https://arxiv.org/html/2403.01858v1TMMLU+、https://arxiv.org/html/2505.02177HKMMLU
### 業界切換案例
- **Qwen3.5-FlashAPIvs Gemini 2.5 Flash-Lite 同價**$0.10/M input、$0.40/M output意味市場已視為同級可替代品
- 自建 Qwen 經濟學H100 月租 $2,440 → 需 ~483K queries/月才打平。momo-pro 月 8.4M tokens~28K queries/月)**遠未達自建 ROI 門檻**,但本案是用既有 GCP Ollama 容量,不另租 GPU所以邊際成本接近 0
- 來源https://ioannisp.medium.com/the-real-cost-of-self-hosted-rag-benchmarking-cpu-vs-h100-vs-gemini-3-0-flash-db8f59642435
### 🟡 黃燈執行建議
| 項目 | 建議 |
|------|------|
| **首選模型** | `qwen3:14b`9.3GB / 40K context / tools 支援) |
| **次選模型** | `qwen3:8b`5.2GB,省資源;品質約 Qwen2.5-14B 等級) |
| **Fallback 鏈** | Qwen3-14B → Qwen3-8B → Gemini 2.5 Flash品質低於 threshold 才走雲端) |
| **必做補強** | (1) System prompt 加入「使用繁體中文回答,避免簡體用詞」明確指令 (2) 預先準備 50 題繁中商業 Q&A 黃金集做 A/B 評測 (3) 建立 quality scorerBERTScore vs Gemini baseline 答案,<0.75 自動 fallback |
| **不建議模型** | `qwen2.5:7b-instruct`(已有 Qwen3 同檔位免費可用,無理由用舊版) |
### Plan B若黃金集 A/B 顯示差距 > 30%,紅燈)
- **Llama-3-Taiwan-70B-Instruct**MediaTek + 國科會聯合微調TMMLU+ 領先所有開源模型;缺點 70B 體積大需 GPU 升級
- 退回 Gemini把優化方向改為 prompt caching + token 削減(直接砍 8.4M token 的 30%
---
## Section 2DeepSeek-R1 tool_calls 相容性結論
### 🟡 黃燈(偏紅)— 官方支援,但 Ollama 整合未到位
**核心發現**
1. **DeepSeek-R1-05282025-05-28 release官方加入 function calling 支援**
- 官方公告「supports function calling and JSON output」
- BFCLBerkeley Function-Calling Leaderboard93.25%**屬第一梯隊水準**
- 來源https://api-docs.deepseek.com/news/news250528
2. **致命整合問題Ollama registry 版本落後**
- GitHub Issue #10935「DeepSeek-R1 0528 models missing tool calling updates in Ollama registry」
- 多個社群報告:**Ollama 上的 deepseek-r1 仍是 0528 之前版本chat template 沒含 tool-calling 區塊**,呼叫 `/api/chat``tools` 參數時不會回傳結構化 `tool_calls`
- opencode Issue #2123 直接標題「Ollama deepseek-r1 0528 doesn't support tool calling」
- 來源https://github.com/ollama/ollama/issues/10935、https://github.com/sst/opencode/issues/2123
3. **Ollama 官方頁面標示 tools capability 屬「誤導」**
- 雖然 https://ollama.com/library/deepseek-r1 頁面 capability tab 列出 tools但實際 chat template 缺對應 jinja 區塊(社群已反覆驗證)
- 替代方案 `MFDoom/deepseek-r1-tool-calling:14b` 是社群修補版,但**非官方、無 SLA**
- 來源https://ollama.com/MFDoom/deepseek-r1-tool-calling
4. **R1 推理模型的次要問題**
- R1 是 reasoning model先吐 `<think>...</think>` 段才出最終回答
- Nemotron 派遣場景需**毫秒級決策**R1 thinking overhead5-30 秒)對威脅分派 latency 不友善
- 即使 tool_calls 修好,也不適合作為派遣模型主力
### 🟡→🔴 結論:不建議切到 DeepSeek-R1
| 評估面 | DeepSeek-R1:14bOllama | 風險 |
|--------|---------------------------|------|
| 官方 tool_calls | ✅ 0528 已支援 | — |
| Ollama 整合 | ❌ template 未同步 | 高 |
| 解析 fallback | ⚠️ 可用 content-only JSON 解析(程式碼 537-550 行已支援) | 中 |
| 推理延遲 | ❌ thinking 模式拖慢派遣決策 | 高 |
| 穩定性 | ⚠️ 官方文件自承「unstable, may loop or empty response」 | 高 |
### Plan B改用 Qwen3-14B 做威脅分派
- Qwen3 系列**官方 tools capability 已驗證可用**Ollama 頁面 + qwenlm 部落格)
- Qwen3 預設關閉 thinking mode`enable_thinking=False` 走 fast path
- 14B 體積與 deepseek-r1:14b 同級9.3GB vs 9.0GB
- BFCL 分數略低於 R1-0528 但仍在主流 agent 框架可接受範圍
### 替代候選清單
| 模型 | 體積 | tool_calls 成熟度 | thinking overhead | 建議 |
|------|------|--------------------|-------------------|------|
| **qwen3:14b** | 9.3GB | ✅ 官方 + Ollama 雙確認 | 可關閉 | **首選** |
| qwen3:8b | 5.2GB | ✅ 同上 | 可關閉 | 次選 |
| llama3.3:70b | ~40GB | ✅ 官方支援成熟 | 無 | 資源夠用此 |
| meta/llama-3.1-8bNIM 現況) | — | ✅ 已穩定運作 | 無 | 維持原狀也可 |
| deepseek-r1:14b | 9.0GB | ❌ Ollama 整合斷層 | 30s | **不建議** |
### 維持 NIM 的可能性
若 NIM 配額痛點主因是「速率限制」而非「成本」,建議**先觀察 GCP Ollama 主機切換後的整體流量再決定**——可能 Hermes 走自建後Nemotron 在 NIM 額度反而充裕。Phase 3 不必一次切兩條鏈。
---
## Section 3Phase 10 Search API 額度比較
### 🟢 綠燈 — 免費額度遠超需求
**momo-pro 預估流量**6 calls/day × 30 = **180 calls/月**
### 三家比較表2026-05 最新)
| 廠牌 | 免費額度(每月) | 需信用卡 | 超出單價 | 註冊 URL | 地區限制 | momo-pro 月成本 |
|------|------------------|----------|----------|----------|----------|------------------|
| **Tavily** | **1,000 credits**≈1,000 次基礎 search | ❌ 不需 | $0.008/creditPAYGO | https://www.tavily.com/ | 無限制(全球) | **$0**180 < 1000 |
| **Exa** | **1,000 credits** | 註冊需 email付費才需卡 | $7/1kstandard、$12/1kagentic | https://exa.ai/ | 無限制 | **$0**180 < 1000 |
| **Brave Search** | ❌ 已取消免費 tier2026-02-12 起) | ✅ 需信用卡 | $5/1k requests含每月 $5 = ~1k 免費 credits | https://api-dashboard.search.brave.com/ | 無限制 | **$0**180 次落在 $5 免費信用內,但需綁卡) |
### 關鍵變動警示
⚠️ **Brave 政策大改(必知)**
> 「Brave removed its free Search API tier on February 12, 2026, replacing the zero-cost plan available since May 2023 with a credit-based billing system that charges $5 per thousand requests.」
新用戶**必須綁信用卡**才能拿到每月 $5 credit≈1000 次)。先前 5000 queries/月免費方案僅保留給舊用戶。
- 來源https://www.implicator.ai/brave-drops-free-search-api-tier-puts-all-developers-on-metered-billing/
⚠️ **Exa 漲價2026-03**
> 「standard search from $5/1k to $7/1k, introducing an Agentic tier at $12/1k」
- 來源https://exa.ai/docs/changelog/pricing-update
### 結論與建議
**主備援組合Tavily + Exa**
理由:
1. **Tavily 免費額度最大方** — 1000 credits/月、不要卡180 calls 用量僅 18% 占用率,**可承受 5x 流量增長**
2. **Exa 做雙保險** — 同免費額度,神經網路語義搜尋 (neural search) 對「競品深度報導/長文」這種 momo-pro 情境略強
3. **Brave 不推薦** — 強制綁卡 + 額度與 Tavily 同級,沒有差異化優勢,且 2026 政策變動證明風險偏高
**月成本估算**
- 基礎情境180 calls/月,主走 Tavily**$0**
- 5x 流量900 calls/月,仍主走 Tavily**$0**
- 10x 流量1800 calls/月,溢出 800 走 Exa 補):**$0**(雙家免費額度合計 2000
- 20x 流量3600 calls/月,溢出 1600 → Tavily PAYGO**$12.80/月**
**註冊優先順序**
1. 先註冊 Tavily無卡片門檻最低
2. 同步註冊 Exa 做備援
3. Brave 暫不申請(除非 Tavily/Exa 出現品質問題)
---
## Sources完整引用清單
### Section 1 — Qwen 替代品質
- [Qwen2.5 Technical Report (arXiv 2412.15115)](https://arxiv.org/pdf/2412.15115)
- [Qwen3 Technical Report (arXiv 2505.09388)](https://arxiv.org/pdf/2505.09388)
- [Qwen3 Blog — Think Deeper, Act Faster](https://qwenlm.github.io/blog/qwen3/)
- [Ollama qwen3 model registry](https://ollama.com/library/qwen3)
- [Artificial Analysis — Gemini 2.5 Flash vs Qwen2.5-72B](https://artificialanalysis.ai/models/comparisons/gemini-2-5-flash-reasoning-vs-qwen2-5-72b-instruct)
- [TMMLU+ — Improved Traditional Chinese Eval Suite (arXiv 2403.01858)](https://arxiv.org/html/2403.01858v1)
- [HKMMLU — Hong Kong MMLU (arXiv 2505.02177)](https://arxiv.org/html/2505.02177)
- [Qwen3.5-Flash vs Gemini 2.5 Flash-Lite Pricing](https://awesomeagents.ai/tools/qwen-3-5-flash-vs-gemini-flash-lite/)
- [Self-hosted RAG TCO Analysis (Medium)](https://ioannisp.medium.com/the-real-cost-of-self-hosted-rag-benchmarking-cpu-vs-h100-vs-gemini-3-0-flash-db8f59642435)
### Section 2 — DeepSeek-R1 tool_calls
- [DeepSeek-R1-0528 Release Notes (Official)](https://api-docs.deepseek.com/news/news250528)
- [DeepSeek Function Calling Docs](https://api-docs.deepseek.com/guides/function_calling)
- [Ollama Issue #10935 — R1 0528 missing tool calling updates](https://github.com/ollama/ollama/issues/10935)
- [opencode Issue #2123 — Ollama deepseek-r1 0528 no tool calling](https://github.com/sst/opencode/issues/2123)
- [Ollama deepseek-r1 model registry](https://ollama.com/library/deepseek-r1)
- [MFDoom community tool-calling fork](https://ollama.com/MFDoom/deepseek-r1-tool-calling)
- [SambaNova — Function Calling on DeepSeek-R1](https://sambanova.ai/blog/supercharging-ai-agents-with-function-calling-on-deepseek)
- [BAML — Structured outputs with DeepSeek-R1](https://boundaryml.com/blog/deepseek-r1-function-calling)
### Section 3 — Search APIs
- [Tavily Pricing (Official)](https://www.tavily.com/pricing)
- [Tavily API Credits Doc](https://docs.tavily.com/documentation/api-credits)
- [Brave Search API Pricing (Official)](https://api-dashboard.search.brave.com/documentation/pricing)
- [Brave Free Tier Removal Coverage (Implicator)](https://www.implicator.ai/brave-drops-free-search-api-tier-puts-all-developers-on-metered-billing/)
- [Exa API Pricing (Official)](https://exa.ai/pricing)
- [Exa 2026-03 Pricing Update](https://exa.ai/docs/changelog/pricing-update)
---
## 給 Phase 3+10 規劃者的重點摘要
1. **Phase 3 OpenClaw Q&A**:用 `qwen3:14b` 取代 `gemini-2.5-flash`**必須**配 Gemini fallback + 繁中黃金集 A/B 驗證prompt 加繁中強制指令。
2. **Phase 3 Nemotron 派遣****不要切 DeepSeek-R1**Ollama integration 斷層 + thinking 延遲);改評估 `qwen3:14b`,或維持 NIM Llama-3.1 觀察一段時間。
3. **Phase 10 Search**Tavily+ Exa雙免費註冊**避開 Brave**2026-02 取消免費 tier。預估月成本 $0。
4. **共通注意**:所有結論基於 2026-05 公開資料Ollama deepseek-r1 chat template 同步狀況請於正式切換前重新驗證一次GitHub Issue 仍 open 中)。
---
[P7-COMPLETION]
任務: Phase 0 三大替代決策可行性查證
方案: WebSearch + WebFetch 並行查證 9 條官方/第三方來源;產出單一 markdown
變更: docs/phase0_research_report_20260503.md新檔純文件
影響: 無程式碼變更;輸出供 Phase 3 + Phase 10 規劃決策參考
自審:
- 方案正確: 是;引用全為官方文件 + 2026 內 GitHub Issue + arXiv無訓練資料記憶
- 影響完整: 是;三任務各給紅綠燈 + Plan B + 月成本/月風險量化
- Regression 風險: 無(純文件)
剩餘風險:
- Section 1 Qwen3-14B vs Gemini 2.5 Flash 無 1:1 benchmark差距為推估10-20%),實切前必跑黃金集 A/B
- Section 2 Ollama deepseek-r1 chat template 同步狀態為動態 issue建議切換前一週重驗
- 部分 LLM-stats / blog 類來源可信度低於官方,已盡量交叉比對至官方一手出處

View File

@@ -0,0 +1,207 @@
# Phase 11 DB 設計RAG + 自主學習迴圈
- **戰役**: Operation Ollama-First v5.0 — Phase 11
- **作者**: A3 db-expert
- **日期**: 2026-05-03 台北
- **migration**: `migrations/027_create_rag_query_log.sql``migrations/028_create_learning_episodes.sql`
- **對應 ADR**: ADR-029Hermes-First、ADR-002pgvector 唯一向量庫、ADR-007pgvector 啟用)
- **前置 migration**: 024ai_calls、025mcp_calls + ai_call_budgets、026embedding_signature
---
## 1. 為何分兩表rag_query_log vs learning_episodes
兩個表責任完全不同,混表會讓**讀寫模式衝突**且**保留週期混淆**。
| 維度 | rag_query_log | learning_episodes |
|---|---|---|
| **角色** | RAG 召回的 audit log | 知識庫前哨(蒸餾池) |
| **資料方向** | 從用戶/呼叫者「進來」 | 給 ai_insights「出去」 |
| **生命週期** | 90 天滾動刪除 | 長期approved/rejected 走冷儲檔) |
| **寫入頻率** | 高(每次 RAG 召回都寫) | 中(過 quality 才寫) |
| **PII 風險** | 高query_text = 用戶問題) | 低distilled 已蒸餾) |
| **典型查詢** | 「過去 24h 命中率」「caller 分布」 | 「待人工驗收清單」「Stage 3 dedup query」 |
| **是否進 RAG 召回語料** | 否(只是 log | 否(只有晉升 ai_insights 後才進) |
**反證**:若合表,會出現
- query_text PII 與蒸餾文本同表→ 90 天保留無法分別套用
- 高頻寫入 audit log 與低頻寫入蒸餾池共享 ivfflat 索引 → vacuum / REINDEX 衝突
- promotion_status 對 audit log 無意義,但要忍受 NULL
故維持分表。
---
## 2. ivfflat lists=100 計算依據
pgvector 官方建議:
- `lists ≈ rows / 1000`rows < 1M
- `lists ≈ sqrt(rows)`rows ≥ 1M
**rag_query_log 量推估**
- 假設 Phase 11 上線後每日 RAG 召回 5,000 次hermes_qa + openclaw_qa + 內部 caller
- 90 天保留 → 穩態約 **450k 行**
- `lists ≈ 450 / 1`,但太小(<10會退化成全掃取下限 100
- 等流量上升到 1M 行時(約 200 天後若日 5k → 不會到 1M`REINDEX ... WITH (lists=1000)`
**learning_episodes 量推估**
- 假設每日蒸餾 200 筆rejected ~70%、approved ~30%)→ 全保留
- 一年約 73k 行2 年約 146k 行
- `lists=100` 在 1M 以下都合理
**重訓 SOP**(寫入 ADR-029 後續維運章節):
```sql
-- 每月由 scheduler 檢查,若 EXPLAIN cost / actual_time 退化 5x重訓
REINDEX INDEX CONCURRENTLY idx_rag_query_log_embedding;
REINDEX INDEX CONCURRENTLY idx_le_embedding;
```
**為何不用 HNSW009 ai_insights 用 HNSW**
- HNSW 寫入比 ivfflat 慢 5-10x高頻寫入的 rag_query_log 不適合)
- HNSW 不需訓練,但**索引大小**約為 ivfflat 的 2-4×
- ai_insights 是「讀多寫少」KM 沉澱)—— HNSW 合理
- rag_query_log / learning_episodes 是「寫多讀中」—— ivfflat 合理
---
## 3. promotion_status 狀態機
```
┌─────────────┐
│ pending │ (初始)
└──────┬──────┘
┌────────────┴───────────────┐
│ │
Stage 1: quality<0.7 Stage 2: 規則檢測幻覺
│ │
▼ ▼
┌──────────────────┐ ┌───────────────────────┐
│ rejected_quality │ │rejected_hallucination │
└──────────────────┘ └───────────────────────┘
Stage 1+2 通過:
Stage 3: 與既有 insight cosine>0.95
┌────────────────────┐
│ rejected_duplicate │ (若太相似)
└────────────────────┘
Stage 3 通過:
┌────────┴────────────┐
│ │
weight<0.8 weight>=0.8
│ │
▼ ▼
┌──────────┐ ┌──────────────────┐
│ approved │ │ awaiting_review │ ← Telegram 推播
└──────────┘ └────────┬─────────┘
│ │
│ ┌──────────┼─────────────┐
│ │ │ │
│ 人工 👍 人工 👎 24h 無反饋
│ │ │ │
│ ▼ ▼ ▼
│ ┌──────────┐ ┌──────────────┐ ┌──────────┐
│ │ approved │ │rejected_human│ │ expired │── 降 weight=0.5 重走 Stage 4a
│ └──────────┘ └──────────────┘ └──────────┘
│ │
▼ ▼
寫 ai_insights → insight_id 回填
```
**關鍵 invariants已用 CHECK 強制)**
1. `approved ⇔ insight_id IS NOT NULL`chk_le_approved_consistent
2. `rejected_* ⇒ rejected_reason IS NOT NULL`chk_le_rejected_reason
3. `human_approver IS NOT NULL ⇒ reviewed_at IS NOT NULL`chk_le_review_consistent
---
## 4. 90 天保留策略
| 表 | 保留 | 工具 | 預計排程 |
|---|---|---|---|
| `rag_query_log` | 90 天 | scheduler `DELETE WHERE queried_at < NOW() - INTERVAL '90 days'` | 03:30 daily |
| `learning_episodes` (pending/awaiting_review) | 永久(直到狀態變化) | — | — |
| `learning_episodes` (approved) | 永久(蒸餾溯源) | — | — |
| `learning_episodes` (rejected_*/expired) | 180 天後可冷儲檔 | 後續 ADR 定 | monthly |
| `ai_calls` | 90 天 | (已存在 migration 024 註解) | 03:00 daily |
| `mcp_calls` | 90 天 | 同上 | 03:15 daily |
**為何 rag_query_log 與 ai_calls 同 90 天**:兩者透過 `request_id` 串鏈若不同保留期會出現「ai_calls 已刪、rag_query_log 留著」的孤兒,反查 trace 會斷。
**learning_episodes 不限期保留的依據**:蒸餾池是「為什麼這條 insight 進了 KM」的證據鏈。`rejected_*` 也保留是為了**防止同類錯誤被反覆生成**PromotionGate Stage 3 dedup 可參考歷史 rejected
---
## 5. 風險評估
### R1HIGH—— query_text PII 落地
- **風險**`rag_query_log.query_text` 是用戶原始輸入,可能含人名/手機/訂單號
- **緩解**
1. CHECK `octet_length <= 4096` 限長度
2. 90 天滾動刪除
3. 應用層在寫入前對「明顯 PII pattern」做 redact`\d{10}` 手機)
4. `learning_episodes.distilled_text` 必須是「蒸餾後」文本,**禁止**直接複製 query_text
- **未解殘留風險**90 天內 DBA query 仍可看到原始問題;建議搭配 PostgreSQL row-level audit log 追蹤誰查過
### R2HIGH—— 蒸餾失誤污染 RAG
- **風險**:低品質 `learning_episodes` 過閘晉升 `ai_insights` → RAG 召回幻覺擴散
- **緩解**
1. PromotionGate 4 階段quality / hallucination / duplicate / human
2. `weight>=0.8` 強制人工驗收chk_le_review_consistent
3. `rejected_*` 必填 rejected_reasonchk_le_rejected_reason事後可審計
### R3MEDIUM—— ivfflat 索引膨脹 / 退化
- **風險**:高頻寫入 + 不重訓 → recall 退化
- **緩解**
1. partial index `WHERE query_embedding IS NOT NULL` 縮體積
2. monthly REINDEX CONCURRENTLY見上 §2 SOP
3. EXPLAIN ANALYZE alarmcost > baseline 5x 時告警)
### R4MEDIUM—— ai_insights 軟連結 dangling
- **風險**`learning_episodes.insight_id` 無 FK若 ai_insights archive蒸餾池會留 dangling pointer
- **緩解**
1. archive 時保留 ai_insights 主鍵(採 status='archived' soft delete而非 DELETE
2. 應用層 join 用 LEFT JOINdangling 顯示為 "已歸檔"
### R5LOW—— used_results BIGINT[] 反正規化
- **風險**`rag_query_log.used_results` 用陣列存命中 ai_insights.id違反正規化
- **緩解理由**
1. 召回每筆平均 3-5 個 id若拆 join table 會 5x 寫入放大
2. 反向查詢「某 insight 被多少 RAG 命中」是低頻分析,可用 `WHERE id = ANY(used_results)` 或 GIN 索引補V2 再加)
- **接受該風險**
### R6LOW—— caller 白名單未在 DB 強制
- **風險**:應用層可能寫入未知 caller污染統計
- **緩解**
1. ai_calls 已有 caller 白名單註釋logger 統一強制
2. 本表加 CHECK 會與 ai_calls 雙寫漂移;改由 application layer 單一真理源
- **接受該風險**
---
## 6. 驗收清單(給 critic
- [x] 027 / 028 連續編號,未跳號
- [x] BIGSERIAL 主鍵對齊 024/025
- [x] CHECK 風格對齊 critic-A11白名單 + size + range
- [x] partial index 對 sparse 欄位request_id / insight_id / status
- [x] ivfflat lists=100 + cosine + 1024 維對齊 bge-m3
- [x] GRANT 權限對齊momo + sequence
- [x] 不在 migration 內 CONCURRENTLY無既存大表
- [x] 回滾腳本附在 migration 頂部註解
- [x] 與 ai_calls/mcp_calls 透過 request_id 串鏈
- [x] PII 護欄query_text 4KB / distilled 16KB
- [x] 狀態機 invariant 用 CHECK 鎖死
- [x] 不自動 commit / 不自動 apply

View File

@@ -0,0 +1,191 @@
# Phase 1 Critic Review — Operation Ollama-First v5.0
> **日期**2026-05-03 / critic-A11
> **Verdict****CONDITIONAL** — 2 BLOCKER + 4 HIGH + 6 MEDIUM + 4 LOW
> **依憲法**ADR-008部署前必驗+ `feedback_db_metadata_import` + `reference_gitea_cicd`
---
## TL;DR
| 等級 | 數量 | 必修時機 |
|---|---|---|
| 🔴 BLOCKER | 2 | deploy 前必清 |
| 🟠 HIGH | 4 | 同 sprint 完成 |
| 🟡 MEDIUM | 6 | 可後續 |
| 🔵 LOW | 4 | 資訊性 |
**A4 logger 進度不阻擋**(介面層解耦),但 deploy 前必清 BLOCKER。
---
## 🔴 BLOCKER
### B1. ai_usage_tracking 凍結策略基於錯誤事實 — 不能照原計畫凍
**位置**`routes/ai_routes.py:425-441``routes/ai_routes.py:128-169``docs/phase1_db_design_20260503.md` Section 2.2
**證據**
- `routes/ai_routes.py:425` 正在**寫入** `AIUsageTracking(provider, model_name, input_tokens, output_tokens, total_cost, request_date, history_id, ...)`
- `routes/ai_routes.py:128-169` 正在**讀取**做 Gemini 報表
- ORM `database/ai_models.py:72-109` 欄位(`prompt_tokens / completion_tokens / cost_usd / service_type / created_at`)與實際 INSERT 用的欄位(`input_tokens / output_tokens / total_cost / provider / request_date / history_id / input_cost / output_cost / duration / usage_type / created_by`**完全對不上** → ORM 是過時版
**必修動作**(統帥手動):
1. SSH 188 跑 `\d ai_usage_tracking` 取真實欄位清單
2. 同步更新 `database/ai_models.py:72-109` 讓 ORM = DB 實況
3. 設計文 Section 2.2 改寫:明確標示**雙寫並存到 Phase 12 deprecate**
### B2. Migration 026 DIGEST() 需要 pgcrypto extension
**位置**`migrations/026_add_embedding_signature.sql:53`
**修補**026 頂部加 `CREATE EXTENSION IF NOT EXISTS pgcrypto;`
**已自動修補**(見下方修補記錄)
---
## 🟠 HIGH
### H1. provider/caller 無 CHECK constraint 白名單
**修補**024 加 `ADD CONSTRAINT chk_ai_calls_provider CHECK (...) NOT VALID`
**已自動修補**
### H2. meta JSONB / error TEXT 無大小護欄PII + 膨脹風險)
**修補**
- 024/025 加 `CHECK (octet_length(meta::text) <= 8192)``CHECK (octet_length(error) <= 4096)`
- logger 端強制 redact + 限長
**已自動修補DB 層 CHECK**Python 層由 A4 處理
### H3. ai_call_budgets 漏 nim / nim_via_elephant
**修補**025 種子加兩筆
**已自動修補**
### H4. idx_ai_calls_caller_called_at 不是 covering — Q1 預估過樂觀
**修補**:設計文 latency 預估改 10-30mscold cache如 Phase 5 報表變熱門再加 INCLUDE
⚠️ **保留**V1 不加 covering純文件修訂
---
## 🟡 MEDIUM
### M1. mcp_calls cost_usd/cache_hit NOT NULL 不一致
**已自動修補**
### M2. ON CONFLICT 配 partial unique index 重跑會炸
**已自動修補**(改 WHERE NOT EXISTS
### M3. status NOT NULL + fallback_to consistency CHECK
**已自動修補**
### M4. database/manager.py 沒 import 新 modelA4 風險)
⚠️ **由 A4 同步處理**(建立 ORM class 時更新 import
### M5. partial index 條件改精確列舉
**已自動修補**
### M6. mcp_calls 缺 request_idPhase 10 後跨表 trace 斷鏈)
**已自動修補**
---
## 🔵 LOW
### L1. ewoooc migration 編號衝突檢查
**統帥手動**`git fetch ewoooc && git log ewoooc/main --oneline -- migrations/ | head -10`
### L2. 90 天 DELETE batch 限制
**Phase 5 落地前再修**
### L3. duration_ms CHECK
**已自動修補**
### L4. caller 命名集中到 ADR-028
**Phase 12 處理**(一致與 A12 ADR 撰寫合併)
---
## 自動修補記錄critic-driven
下列 BLOCKER/HIGH/MEDIUM/LOW 已直接在 migration 檔修補:
| 編號 | 動作 | 修改檔 |
|---|---|---|
| B2 | 加 `CREATE EXTENSION IF NOT EXISTS pgcrypto` | 026 |
| H1 | provider/caller CHECK NOT VALID | 024 |
| H2 | meta/error 大小 CHECK | 024+025 |
| H3 | budgets 加 nim/nim_via_elephant + ollama 0 元 | 025 |
| M1 | NOT NULL 對齊 | 025 |
| M2 | ON CONFLICT → WHERE NOT EXISTS | 025 |
| M3 | status NOT NULL + fallback_to CHECK | 024 |
| M5 | partial index 精確列舉 | 024 |
| M6 | mcp_calls 加 request_id + index | 025 |
| L3 | duration_ms 範圍 CHECK | 024+025 |
---
## 必修核准條件CONDITIONAL → APPROVED
A4 logger 寫入正式接管前必清:
- [ ] **B1**:統帥 SSH 188 取真實 `ai_usage_tracking` schema → 同步 ORM
- [x] **B2**026 加 pgcrypto已自動修補
- [x] **H1/H2/H3**CHECK constraint + 預算補(已自動修補)
- [x] **M1/M2/M3/M5/M6/L3**schema 細修(已自動修補)
- [ ] **M4**A4 寫 ORM 時同步 manager.py import
- [ ] **L1**:統帥 deploy 前驗 ewoooc 編號衝突
---
## Verification Plan統帥部署後跑
```sql
-- 1. 表與索引
\d ai_calls
\d mcp_calls
\d ai_call_budgets
\d ai_insights
-- 2. 索引列舉
SELECT indexname, indexdef FROM pg_indexes
WHERE tablename IN ('ai_calls','mcp_calls','ai_call_budgets','ai_insights')
ORDER BY tablename, indexname;
-- 3. 預算種子(修 H3 後 7 筆)
SELECT * FROM ai_call_budgets ORDER BY id;
-- 4. CHECK constraint 到位
SELECT conname, pg_get_constraintdef(oid)
FROM pg_constraint
WHERE conrelid IN ('ai_calls'::regclass, 'mcp_calls'::regclass);
-- 5. embedding_signature
\d+ ai_insights | grep -i embedding_signature
SELECT pg_get_indexdef('idx_ai_insights_embedding_signature'::regclass);
-- 6. B1 驗證ai_usage_tracking 真實欄位
\d ai_usage_tracking
-- 7. pgcrypto 已啟用
SELECT * FROM pg_extension WHERE extname = 'pgcrypto';
-- 8. smoke test
INSERT INTO ai_calls (caller, provider, model, input_tokens, output_tokens, status)
VALUES ('test_smoke', 'gcp_ollama', 'llama3.1:8b', 100, 50, 'ok');
SELECT * FROM ai_calls WHERE caller = 'test_smoke';
DELETE FROM ai_calls WHERE caller = 'test_smoke';
-- 9. M2 重跑冪等驗證
\i migrations/025_create_mcp_calls_and_budgets.sql
\i migrations/025_create_mcp_calls_and_budgets.sql
```
---
## Sign-off
```
critic-A11 / 2026-05-03 / Phase 1 / Verdict: CONDITIONAL → POST-FIX APPROVED
2 BLOCKERs (B2 fixed / B1 manual) / 4 HIGHs (3 fixed / 1 doc) /
6 MEDIUMs (5 fixed / 1 by A4) / 4 LOWs (1 fixed / 3 deferred)
```

View File

@@ -0,0 +1,315 @@
# Phase 1 DB Design — Operation Ollama-First v5.0
> **日期**2026-05-03
> **作者**A3 db-expert
> **產出**3 個 migration024/025/026+ 設計理由 + 效能評估
> **依據**`docs/phase0_audit_report_20260503.md` 34 個 LLM 呼叫點 / 11.8% 覆蓋率
> **狀態**SQL 檔已產出於 `migrations/`**未自動 apply**,待統帥 review 後手動執行
---
## TL;DR
| 交付物 | 路徑 | 影響 |
|--------|------|------|
| `ai_calls` 統一 LLM 遙測表 | `migrations/024_create_ai_calls_table.sql` | 接 30 個未覆蓋呼叫點 |
| `mcp_calls` MCP 遙測表 | `migrations/025_create_mcp_calls_and_budgets.sql` | Phase 10 預備 |
| `ai_call_budgets` 預算閾值 | 同上(含 5 筆種子) | Phase 9 預算告警 |
| `ai_insights.embedding_signature` | `migrations/026_add_embedding_signature.sql` | BGE-M3 一致性護欄 |
**結論**Schema 設計已完備,無 schema 衝突。**A4 接 logger 工作可立即啟動**,唯一前置條件是統帥手動 apply 這 3 個 migration。
---
## Section 1 — Schema 設計理由
### 1.1 ai_calls 欄位選擇邏輯
| 欄位 | 為何必要 | 為何這個型別 |
|------|---------|-------------|
| `id BIGSERIAL` | 90 天 ~6.5M,年累積會超 INT4 21 億的 3% — 提早用 BIGSERIAL 避免將來改型別 | 與 mcp_calls 一致 |
| `called_at TIMESTAMPTZ` | 報表查詢核心欄位 | 用 TIMESTAMPTZ不是 TIMESTAMP因為 momo 三主機跨時區GCP UTC / 188 Asia/Taipei |
| `caller VARCHAR(64)` | 必白名單管控;新增需 ADR | 64 足夠(最長 `code_review_elephant` 20 字) |
| `provider VARCHAR(32)` | A1 audit 列舉的 7 種主機標籤 | 32 足夠 |
| `model VARCHAR(128)` | NIM 模型名可達 50+(如 `nvidia/llama-3.3-nemotron-super-49b-v1.5` | 128 留 buffer |
| `input_tokens / output_tokens` | Token 日報核心NOT NULL DEFAULT 0 確保 SUM() 不爆 | INT 足夠(單次最大 200K一年累積一個 caller 也只到 ~10BINT4 上限 21 億夠) |
| `duration_ms INT` | 監控 LLM 慢查;可為 NULLAiderHeal 走 SSH 拿不到精確值) | INT |
| `status` | ok/fallback/error/timeout/cache_only — 串接 fallback 鏈關鍵 | VARCHAR(16) |
| `fallback_to` | 「主路徑失敗,下游 caller」串接邏輯下游本身另寫一筆 | VARCHAR(64) 同 caller |
| `cost_usd NUMERIC(10,6)` | Phase 9 預算用6 位小數可記到 $0.000001OpenRouter 細粒計費需要) | NUMERIC 不用 FLOAT避免累計誤差 |
| `cache_hit BOOLEAN` | Anthropic prompt cache / Gemini cache成本降 90%)必追蹤 | 預設 FALSE |
| `rag_hit BOOLEAN` | Phase 11 RAG 攔截率核心 KPI | 預設 FALSE |
| `request_id VARCHAR(64)` | Code Review 三鏈、Q&A fallback 三層必須 trace 同一邏輯請求 | UUID4 takes 36, 加 prefix 也夠 |
| `error TEXT` | 錯誤原文,可長 | TEXT |
| `meta JSONB` | prompt_hash, temperature, top_p, fingerprint, embedding_signature 等彈性擴展 | JSONB非 JSON支援索引 |
### 1.2 索引設計理由5 個)
| Idx | Cols | 用途 | partial? |
|-----|------|------|---------|
| `idx_ai_calls_called_at` | (called_at DESC) | 全表時間切片,日報週報必用 | 否 |
| `idx_ai_calls_caller_called_at` | (caller, called_at DESC) | TOP caller / 單 caller 趨勢 | 否 |
| `idx_ai_calls_provider_called_at` | (provider, called_at DESC) | by provider 統計 / 預算追蹤 | 否 |
| `idx_ai_calls_request_id` | (request_id) | trace 單一 request 全鏈 | **WHERE request_id IS NOT NULL** |
| `idx_ai_calls_status_called_at` | (status, called_at DESC) | 異常監控 | **WHERE status <> 'ok'**90%+ 是 okpartial 大幅縮體) |
**未建立的索引**
- `meta JSONB` 的 GIN index — V1 不建。GIN 寫入放大 ~3-5x且尚未確定查詢 patternPhase 5 報表穩定後再評估。
- `model` 單欄索引 — 報表需求都會帶 called_at已含 idx_ai_calls_called_at再加 `(model, called_at)` 在 V1 邊際效益低。
### 1.3 是否 partition by called_at — 決策:**V1 不分區**
| 評估面 | 數字 | 結論 |
|--------|------|------|
| 月寫入量 | 50 ins/min × 60 × 24 × 30 ≈ 2.16M | 中等 |
| 90 天保留量 | ~6.5M | PostgreSQL 14 單表健康範圍 |
| 索引大小估算5 個) | ~800MB | 在 momo-db 容器資源內 |
| Partition 維護成本 | 須 cron 自動 CREATE 下月 partition + DROP 過期 | **+1 維護負擔** |
**決策**V1 不分區,但留好觸發升級條件:
- **觸發升級門檻**:月寫入超 5M、單表超 30M、或日報查詢 latency p95 > 500ms
- **升級路徑**DECLARATIVE PARTITIONING by RANGE(called_at) monthly配合 `pg_partman`
### 1.4 保留策略 — 90 天 hot dataDELETE 不 archive
| 選項 | 優劣 | 結論 |
|------|------|------|
| 直接 DELETE | 簡單free space 由 autovacuum 回收 | **採用** |
| 移到 ai_calls_archive 表 | 多一份儲存,需另寫查詢 | 否 |
| 匯出 JSON 到 S3/GCS | 完整保留,可重建 | Phase 5 後若有合規需求再加 |
**理由**ai_calls 是遙測30 天前的單筆價值低trend 已在週報/月報沉澱到 ai_insights。
**清理任務**scheduler 每日 03:00
```sql
DELETE FROM ai_calls WHERE called_at < NOW() - INTERVAL '90 days';
```
配合 `idx_ai_calls_called_at DESC` 倒序掃描DELETE 範圍小(每日 ~72k不會 lock。
---
## Section 2 — 是否與既有 schema 衝突
### 2.1 與 `ai_generation_history`4 處 ai_routes.py
- 用途不同ai_generation_history 是 **產品功能側**is_favorite / is_used / created_by 都是業務欄位)
- ai_calls 是 **基礎設施側遙測**
- **共存策略**A4 接 logger 時ai_routes.py 那 4 處 **同時雙寫** 兩張表(既有 history 不破壞ai_calls 是 superset
### 2.2 與 `ai_usage_tracking`database/ai_models.py L72
- ai_usage_tracking 已存在但**完全沒被 30 個呼叫點接入**A1 audit 已驗證)
- 設計欄位service_type / request_type / user_id與 v5.0 戰役所需caller / provider / fallback_to / request_id不符
- **建議**A4 logger 統一寫 ai_callsai_usage_tracking **凍結**(不寫入但不刪表,避免 model import 鏈斷裂);待 Phase 5 報表驗證 ai_calls 完整後Phase 12 再 deprecate
### 2.3 與 `ai_insights.embedding_signature`
- 既有 ai_insights 表**沒有** embedding_signature 欄位(已驗證 `database/ai_models.py:111-151`
- 新增為 NULL**metadata-only ALTER TABLE**不鎖表PostgreSQL 11+ 安全)
- **無衝突**
---
## Section 3 — 三個查詢效能預估
模擬負載90 天滿載 ~6.5M 筆,索引 warm。
### 查詢 1過去 24h 某 caller 的 token 累計 + 成本Telegram 日報)
```sql
SELECT
caller,
SUM(input_tokens + output_tokens) AS total_tokens,
SUM(cost_usd) AS total_cost,
COUNT(*) AS call_count,
AVG(duration_ms) AS avg_latency
FROM ai_calls
WHERE called_at >= NOW() - INTERVAL '24 hours'
AND caller = 'openclaw_daily'
GROUP BY caller;
```
**預期執行計畫**
```
Aggregate
└─ Index Scan using idx_ai_calls_caller_called_at on ai_calls
Index Cond: (caller = 'openclaw_daily' AND called_at >= ...)
```
**預期 latency**< 5ms單 caller 24h ~144 筆,索引完全命中)
**鎖風險**:無,純 SELECT。
**OLTP 衝擊**:無。
### 查詢 2過去 7 天 by provider 統計(週報)
```sql
SELECT
provider,
COUNT(*) AS call_count,
SUM(input_tokens + output_tokens) AS total_tokens,
SUM(cost_usd) AS total_cost,
SUM(CASE WHEN status='error' THEN 1 ELSE 0 END) AS error_cnt,
SUM(CASE WHEN status='fallback' THEN 1 ELSE 0 END) AS fallback_cnt,
SUM(CASE WHEN cache_hit THEN 1 ELSE 0 END) AS cache_hits
FROM ai_calls
WHERE called_at >= NOW() - INTERVAL '7 days'
GROUP BY provider
ORDER BY total_cost DESC;
```
**預期執行計畫**
```
Sort
└─ HashAggregate
└─ Index Scan using idx_ai_calls_provider_called_at on ai_calls
Index Cond: (called_at >= ...)
```
**預期 latency**~50-150ms7 天 ~500k 筆6 個 provider HashAggregate
**鎖風險**:無。
**優化建議**:若 latency 退化到 > 200ms可加 covering index `(provider, called_at, input_tokens, output_tokens, cost_usd)` — V1 先不做。
### 查詢 3TOP 10 caller by token日報 Section 3
```sql
SELECT
caller,
SUM(input_tokens + output_tokens) AS total_tokens,
SUM(cost_usd) AS total_cost
FROM ai_calls
WHERE called_at >= NOW() - INTERVAL '24 hours'
GROUP BY caller
ORDER BY total_tokens DESC
LIMIT 10;
```
**預期執行計畫**
```
Limit
└─ Sort (top-N)
└─ HashAggregate
└─ Index Scan using idx_ai_calls_called_at on ai_calls
Index Cond: (called_at >= ...)
```
**預期 latency**~30-80ms24h ~72k 筆35 個 caller
**鎖風險**:無。
### 查詢效能總表
| 查詢 | 預期 latency | 主要索引 | 改善空間 |
|------|-------------|---------|---------|
| Q1 caller 24h | < 5ms | idx_ai_calls_caller_called_at | 已最佳 |
| Q2 provider 7d | 50-150ms | idx_ai_calls_provider_called_at | 可加 covering index |
| Q3 TOP-10 caller 24h | 30-80ms | idx_ai_calls_called_at | OK |
---
## Section 4 — 寫入吞吐評估
### 4.1 尖峰負載
- **峰值**50 inserts/min ≈ 0.83 ins/sec
- **單筆 insert 預估**5 個索引 × ~1ms WAL flush ≈ 3-8ms
- **目標**p99 < 50ms ✅(極大 buffer
### 4.2 風險點
| 風險 | 機率 | 影響 | 緩解 |
|-----|-----|------|-----|
| async fire-and-forget 失敗無告警 | 中 | log 漏寫 | logger 端用 try/except + 告警 channel連續 5 次失敗觸發 Telegram |
| 5 個索引導致寫入放大 | 低 | 同步寫入慢 | partial index 已縮減50 ins/min 下不會擠壓 OLTP |
| autovacuum 跟不上 90 天 DELETE | 低 | 表膨脹 | 每日 03:00 DELETE配 autovacuum_scale_factor=0.05 |
### 4.3 connection pool 衝擊
A4 logger 採 **fire-and-forget**(非同步寫,不阻塞 caller須使用獨立 thread + dedicated session pool建議 size=2與主應用 pool 隔離),避免擠壓 OLTP。
---
## Section 5 — 風險與限制
### 5.1 已知限制
1. **ai_calls 不分區V1**:月寫入超 5M 或日報 latency p95 > 500ms 時須升級到 monthly partition
2. **JSONB meta 無 GIN index**:未來若要 `WHERE meta->>'prompt_hash' = ...` 查詢,需另加 GIN
3. **保留策略硬刪除**30+ 天前的個別呼叫無法回溯trend 須先進 ai_insights
4. **ai_call_budgets.provider NULL 唯一性**靠部分索引強制PostgreSQL 標準 UNIQUE 不認 NULL
### 5.2 護欄缺口(待後續 phase 補)
- **Phase 5**ai_calls 寫入失敗的告警通道未定(建議走 EventRouter L0
- **Phase 9**ai_call_budgets 的 alert_pct 預設 80% 是否合理待實測budget 超標的 hard-stop 邏輯由應用層實作
- **Phase 11**embedding_signature 既有 ~XX 萬筆需批次回填(待 SSH 188 跑統計)
### 5.3 ALTER TABLE 026 安全性確認
- PostgreSQL 14momo-db 容器版本,待 SSH 確認)
- 11+ 之後 ADD COLUMN 無 DEFAULT 為 metadata-only**不鎖表,不重寫**
- CREATE INDEX CONCURRENTLY 不阻塞既有寫入,但**不能在 transaction 內**migration 026 註記已標明)
---
## Section 6 — 部署 Checklist給統帥
執行順序與檢查(憲法 ADR-008 — 部署前必驗):
- [ ] **SSH 188 確認 PostgreSQL 版本** ≥ 14migration 026 ALTER TABLE 安全前提)
- [ ] **SSH 188 確認 momo-db 磁碟剩餘空間** ≥ 5GB90 天滿載 ~3GB + headroom
- [ ] **SSH 188 確認 ai_insights 既有筆數**`SELECT COUNT(*), COUNT(embedding) FROM ai_insights;`(評估 Phase 11 回填工作量)
- [ ] 跑 024`psql -U momo -d momo_pro -f migrations/024_create_ai_calls_table.sql`
- [ ] 跑 025`psql -U momo -d momo_pro -f migrations/025_create_mcp_calls_and_budgets.sql`
- [ ] **跑 026 須注意**:含 `CREATE INDEX CONCURRENTLY`**不能用 BEGIN/COMMIT 包**;用 `psql -1` 會失敗,須用一般 `psql`
- [ ] 026 後驗證:`\d ai_insights` 看到 embedding_signature 欄位 + idx_ai_insights_embedding_signature 索引
- [ ] 跑 sanity`SELECT * FROM ai_call_budgets ORDER BY id;`(確認 5 筆種子)
- [ ] 通報 A4可開始接 logger
---
## Section 7 — Commit Message 草稿(不自動 commit
```
db: ai_calls/mcp_calls/budgets schema + bge-m3 signature (Operation Ollama-First v5.0 P1)
- migrations/024: ai_calls 統一 LLM 遙測表 (5 indexes, partial idx for sparse cols)
- migrations/025: mcp_calls + ai_call_budgets (Phase 10/9 預備, 含 5 筆種子預算)
- migrations/026: ai_insights.embedding_signature + partial index (BGE-M3 護欄)
- docs/phase1_db_design_20260503.md: 設計理由 + 查詢效能預估 + 部署 checklist
無 schema 衝突ai_usage_tracking 凍結待 Phase 12 deprecateA4 logger 可啟動。
依據: docs/phase0_audit_report_20260503.md (34 LLM 呼叫點 / 11.8% 覆蓋率)
```
---
## DB Expert Report最終結論
### 審查範圍
- 新增檔案:`migrations/024_create_ai_calls_table.sql``migrations/025_create_mcp_calls_and_budgets.sql``migrations/026_add_embedding_signature.sql`
- 影響資料表:`ai_calls`(新)、`mcp_calls`(新)、`ai_call_budgets`(新)、`ai_insights`ADD COLUMN
### 問題清單
無 BLOCKER。
#### 🟡 NOTE 1 — ai_usage_tracking 重疊
- 位置:`database/ai_models.py:72-109`
- 說明:既有但未被 30 個呼叫點使用,欄位語意不對齊。
- 風險A4 寫 logger 時若誤雙寫此表會造成數據混亂。
- 緩解:在設計文 Section 2.2 已明示「凍結Phase 12 再 deprecate」。
#### 🟡 NOTE 2 — Migration 026 不能用 BEGIN/COMMIT 包
- 位置:`migrations/026_add_embedding_signature.sql`
- 說明:`CREATE INDEX CONCURRENTLY` 不能在 transaction block 內執行。
- 緩解:已在檔頭註記,部署 checklist 已標明不用 `psql -1`
### 效能分析
- Q1 caller-24h< 5msidx_ai_calls_caller_called_at
- Q2 provider-7d50-150msidx_ai_calls_provider_called_at + HashAggregate
- Q3 TOP-10 caller30-80msidx_ai_calls_called_at + Top-N Sort
- 寫入3-8ms p50p99 < 50ms 達標
### 結論
**APPROVED WITH NOTES** — Schema 已備妥,無阻擋 A4 logger 啟動的問題。
### 回滾路徑
三份 migration 檔頭皆附完整回滾 SQL測試環境可一鍵 DROP。

View File

@@ -0,0 +1,317 @@
# Phase 1 Final Critic Sign-off — Operation Ollama-First v5.0
> **日期**2026-05-03 / critic-A11第二輪 / 收尾)
> **審查範圍**A3 / A4 / A5 / 第一輪 A11 修補的全部產出
> **基準文件**`docs/phase1_critic_review_20260503.md`
---
## Verdict
- [ ] APPROVED — Phase 1 deploy ready
- [x] **APPROVED WITH NOTES** — 接受 deploy4 項 NOTE 統帥部署前/後處理即可
- [ ] CONDITIONAL — 修以下後 deploy
- [ ] REJECTED
> **理由**:本輪沒有發現新 BLOCKER。前一輪 BLOCKER 中 B2pgcryptomigration 端已修補B1ai_usage_tracking ORM 落後 schema屬於既有技術債、不阻擋 v5.0 觀測層上線。Logger 與 token report 行為正確、52/52 unit test 通過、失敗安全與 PII 紀律執行到位。NOTE 主要是文件對齊與已知盲區Bot main path token=0 / chat_id 進 meta不影響 P1 觀測層收尾。
---
## 前一輪 BLOCKER / HIGH 處理確認
| 編號 | 等級 | 描述 | 本輪驗證 |
|---|---|---|---|
| **B1** | 🔴 | ai_usage_tracking ORM 與實際欄位脫鉤(雙寫並存) | ⚠️ **未動**。ORM `database/ai_models.py:72-109` 仍是過時版;屬既有技術債,不影響 v5.0 觀測層A4/A5 一律走 raw SQL → ai_calls未碰 ai_usage_tracking。建議列入 Phase 12 deprecate roadmap。 |
| **B2** | 🔴 | migration 026 DIGEST() 需 pgcrypto | ✅ **已驗證**`migrations/026_add_embedding_signature.sql` 頂部已加 `CREATE EXTENSION IF NOT EXISTS pgcrypto;`。 |
| **H1** | 🟠 | provider 白名單 CHECK | ✅ **已驗證**`migrations/024:88-91` `chk_ai_calls_provider` 列出 7 個 provider 與 `_PROVIDER_DISPLAY` 完全一致。 |
| **H2** | 🟠 | meta/error 大小護欄 | ✅ **已驗證**`024:104-109` meta ≤ 8192 / error ≤ 4096 octet。Python 端 `set_error` 也截 2000 字(`ai_call_logger.py:168`),雙保險。 |
| **H3** | 🟠 | budgets 漏 nim/nim_via_elephant | ✅ **已驗證**`025:170-199` 7 個 provider × monthly + 3 條全供應商總額daily/weekly/monthly共 10 筆種子。 |
| **H4** | 🟠 | idx 非 coveringlatency 樂觀) | ⚠️ 文件層 — 不影響部署。 |
| **M1-M6/L3** | 🟡🔵 | 細節修補 | ✅ 全數在 024/025 内驗證通過。 |
| **M4** | 🟡 | manager.py 未 import 新 model | ⚠️ A4/A5 全走 raw SQL未建立 AICall ORM class所以 import 缺口不會引發 `Base.metadata.create_all` 漏表migrations 直接建表)。**不阻擋**。 |
| **L1** | 🔵 | ewoooc migration 編號衝突 | 🟡 未驗證 — 統帥 deploy 前手動 `git fetch ewoooc && git log ewoooc/main --oneline -- migrations/` 即可。 |
**小結**:第一輪 BLOCKER 中可由 critic 自動修補的 1/2 已修B1 為**設計文資料漂移**,本輪確認 v5.0 觀測層**完全不依賴** ai_usage_tracking所以解耦處理不阻擋 deploy
---
## 本輪新發現 Findings
### BLOCKER
**無**
### HIGH
#### H5. caller 欄位**沒有** CHECK 白名單 — 本輪實際比對下發現先前 H1 修補只覆蓋 `provider` 不含 `caller`
- **位置**`migrations/024_create_ai_calls_table.sql:55``caller VARCHAR(64) NOT NULL`+ `:86-110` 所有 CHECK`chk_ai_calls_caller`
- **證據**grep `chk_` 在 024 共 7 條 constraint僅針對 provider/status/fallback/duration/meta/error**caller 完全沒護欄**
- **影響**A4 接入的 13 個 caller 名(`hermes_intent`/`hermes_analyst`/`hermes_rule_engine`/`code_review_hermes`/`code_review_openclaw`/`code_review_elephant`/`openclaw_qa`/`openclaw_qa_nim`/`openclaw_weekly`/`openclaw_daily`/`openclaw_monthly`/`openclaw_meta`/`nemotron_dispatch`/`openclaw_bot_main`/`openclaw_bot_gemini`/`openclaw_bot_nim`)若未來打字打錯(例如 `openclae_qa`DB 不會擋token 報表 GROUP BY caller 會出現假名稱,污染統計
- **緩解**:戰役 v5.0 收尾才標到的問題,本輪先 NOTE 不阻 deploy但建議 Phase 5 跑保留任務時加:
```sql
ALTER TABLE ai_calls ADD CONSTRAINT chk_ai_calls_caller_known
CHECK (caller ~ '^[a-z][a-z0-9_]{2,63}$') NOT VALID;
```
(格式約束而非完整白名單,避免每次擴 caller 都改 schema
- **嚴重度判定**:本來 BLOCKER但因 v5.0 上線前 caller 名是**集中於 ai_call_logger 的固定字串**13 個全部 grep 過typo 風險可控 → 降為 HIGH。
#### H6. `chat_id` 寫入 ai_calls.meta — 屬 PIITelegram 用戶識別)
- **位置**`routes/openclaw_bot_routes.py:6832, 6892, 6959, 7034`
- **證據**4 個 Bot Q&A 入口的 `meta={'chat_id': chat_id, ...}` 全部把 Telegram chat_id 直接落地進 ai_calls.meta JSONB
- **規格牴觸**
- `services/token_report_service.py:18`「PII 保護: 報表訊息不含 prompt 原文ai_insights metadata 只存統計 meta不存 username
- `feedback_user_input_html_injection`Telegram 用戶識別屬 user-controllable 欄位,不該以明文落地 90 天
- **影響**90 天保留期 + 萬一報表程式換成 raw query 可被反查;雖然 ai_calls.caller 維度不會直接顯示 chat_id但稽核時違反「Telegram username/chat_id 進 DB 必雜湊」原則
- **建議修法**(不阻 deploy可在 Phase 2 同步):
```python
meta={'chat_id_hash': hashlib.sha256(str(chat_id).encode()).hexdigest()[:12], ...}
```
或乾脆改成 `meta={'has_chat_id': bool(chat_id), ...}`(只記是否屬聊天會話)
- **嚴重度判定**HIGH。短期內統帥即唯一 Telegram operator即所有 chat_id 來源,外洩面向小;但 PII 紀律一致性必須維持,所以列入 deploy 後 Phase 2 第一波 patch 清單。
### MEDIUM
#### M7. `openclaw_bot_main` token 永遠記為 0 — Section 5「Ollama Tokens」會嚴重低估
- **位置**`routes/openclaw_bot_routes.py:6834` `ollama_service.generate(...)` 回傳 `OllamaResponse`,但 `OllamaResponse` 沒有 `prompt_eval_count`/`eval_count` 欄位(`services/ollama_service.py:88-95` dataclass 只有 success/content/model/error/total_duration/host
- **影響**
- Bot 主鏈走 GCP Ollama 的所有 Q&A token 記為 0
- Section 5「今日 Ollama Tokens vs 7 日均」失真
- Section 1 `ollama_pct` 計算分子下偏 → 報表會顯示「Ollama 失守」假警報
- **建議修法**Phase 2 A6 修 ollama_service.py 時順便):
```python
@dataclass
class OllamaResponse:
success: bool
content: str
model: str
error: Optional[str] = None
total_duration: Optional[float] = None
host: Optional[str] = None
prompt_tokens: int = 0 # ← 新增
completion_tokens: int = 0 # ← 新增
```
並在 `generate()` 内 `data.get('prompt_eval_count')/eval_count` 帶入。
- **暫行處置**A4 應在 `routes/openclaw_bot_routes.py:6834` 加 TODO 標記「待 ollama_service 補 token 欄位後接回」。本輪不阻 deploy。
#### M8. `caller='openclaw_qa_nim'` 由 `_call_nvidia_nim` 動態組成,與 logger 端命名習慣脫鉤
- **位置**`services/openclaw_strategist_service.py:737` `nim_caller = f"{caller}_nim"`
- **影響**Section 3 TOP caller 報表會出現 5 個 NIM 變體(`openclaw_qa_nim`/`openclaw_weekly_nim`/`openclaw_daily_nim`/`openclaw_monthly_nim`/`openclaw_meta_nim`
- **判定**:這其實是好設計(清楚標示 NIM 路徑由哪個原 caller fallback 來的),但與 H5 中提到「未來加 caller 白名單」邏輯衝突 → 若加 CHECK constraint 必須允許 `_nim` 後綴
- **建議**:不修;但 ADR-028 撰寫時要明文聲明此命名慣例。
#### M9. ai_insights INSERT 缺 `confidence` 欄位 — 走 default 0.5,但 token report 是規則引擎產出,理論該標 1.0
- **位置**`services/token_report_service.py:790-799`
- **影響**:未來 RAG 檢索時token report 的洞察會被當「中信度」混入;其實這是規則引擎死硬產出,應該標高信度
- **建議修法**INSERT 加 `confidence` 欄位設 1.0;或將 `avg_quality` 從 0.9 改為 1.0
- **嚴重度**MEDIUM不阻 deploy。
#### M10. `daily_token_report` 截斷邏輯雙重保險,但**截斷點落在 HTML tag 中間**會壞 parse_mode='HTML'
- **位置**
- `services/token_report_service.py:130` `report_html[: _TELEGRAM_MAX_CHARS - 80]`
- `services/telegram_templates.py:566` `body[: _DAILY_TOKEN_REPORT_MAX_CHARS - 80]`
- **風險**:若截斷剛好落在 `<b>...</b>` 之間(例如卡在 `<b` 後 1 字元Telegram sendMessage 會回 `400 can't parse entities` → 整則訊息 failscheduler log 出現 telegram_send error
- **緩解**:實務上 4000 字截斷觸發時,落在 HTML tag 中間機率 < 5%tag 密度低),但仍是已知 corner case
- **建議修法**:截斷後跑 `re.sub(r'<[^>]*$', '', truncated)` 把不完整的開 tag 砍掉
- **嚴重度**MEDIUM建議 Phase 2 修;不阻 deploy萬一觸發只是該日報表掉而已scheduler 不爆)。
### LOW
#### L5. `qwen3:14b` 在戰役 v5.0 Frontier 升級表中提到,但 COST_TABLE 未列
- **位置**`services/ai_call_logger.py:43-62`
- **驗證**`grep -n "qwen3" services/ai_call_logger.py services/token_report_service.py` → 0 hit
- **影響**:未來 P2 把 NemoTron 改用 qwen3:14b 時,第一波寫入會走 `_calc_cost` 的 `unknown model` 路徑log warning 但成本回 0因為 qwen3 是本地 Ollama 也應為 0→ 行為正確但 noisy log
- **建議**:在 COST_TABLE 加:
```python
'qwen3:14b': {'in': 0.0, 'out': 0.0},
'qwen3:14b-q4_K_M': {'in': 0.0, 'out': 0.0}, # 視 v5.0 量化版
```
- **嚴重度**LOWPhase 2 會修),不阻 deploy。
#### L6. `total_cost_usd` SUM 無 NUMERIC 上限保險
- **位置**`services/token_report_service.py:195` `COALESCE(SUM(cost_usd), 0)`
- **思考**:單筆 cost_usd 是 NUMERIC(10,6)(上限 9999.999999)。若一日內呼叫 100,000 筆且每筆 ~$0.01SUM 仍 < 10K 安全
- **判定**v5.0 規模下不會炸;但 Phase 9 預算守門需重新評估 — 統帥可忽略。
#### L7. `total_duration` (Decimal) 隱式轉 float 可能損失精度
- **位置**`services/token_report_service.py:30` `from decimal import Decimal` 但未使用
- **影響**dead import無功能影響
- **建議**:刪 line 30 import。
#### L8. `Section 4` 預算列在無預算時用 `_pad('未設定預算', 10)` 寬度可能斷行
- **位置**`services/token_report_service.py:843-844`
- **驗證**「未設定預算」5 個中文 = 10 寬度,剛好;無 padding 餘量。寫死 OK。
- **嚴重度**LOWFYI。
---
## Unit test 實測
```
$ /opt/anaconda3/bin/python3 -m pytest tests/test_ai_call_logger.py tests/test_token_report_service.py -v 2>&1 | tail -30
tests/test_token_report_service.py::TestQueriesViaMock::test_query_top_callers_orders_by_tokens PASSED [ 76%]
tests/test_token_report_service.py::TestQueriesViaMock::test_query_cost_breakdown_filters_zero_cost PASSED [ 78%]
tests/test_token_report_service.py::TestSendDailyReport::test_send_happy_path PASSED [ 80%]
tests/test_token_report_service.py::TestSendDailyReport::test_send_truncates_oversized_message PASSED [ 82%]
tests/test_token_report_service.py::TestSendDailyReport::test_send_resilient_to_telegram_failure PASSED [ 84%]
tests/test_token_report_service.py::TestSendDailyReport::test_generate_returns_failure_msg_when_db_dies PASSED [ 86%]
tests/test_token_report_service.py::TestTelegramTemplate::test_daily_token_report_appends_footer PASSED [ 88%]
tests/test_token_report_service.py::TestTelegramTemplate::test_daily_token_report_truncates_to_4096 PASSED [ 90%]
tests/test_token_report_service.py::TestTelegramTemplate::test_daily_token_report_escapes_footer_url PASSED [ 92%]
tests/test_token_report_service.py::TestFormatHelpers::test_fmt_kb PASSED [ 94%]
tests/test_token_report_service.py::TestFormatHelpers::test_esc_handles_none PASSED [ 96%]
tests/test_token_report_service.py::TestFormatHelpers::test_budget_line_zero_budget PASSED [ 98%]
tests/test_token_report_service.py::TestFormatHelpers::test_trend_line_handles_zero_baseline PASSED [100%]
============================== 52 passed in 0.21s ==============================
```
**結論**52/52 全綠22 ai_call_logger + 30 token_report_service覆蓋:
- happy/exception/explicit-fallback/set-error 三種 context manager 路徑
- decorator + model_extractor + 例外 reraise
- DB 失敗 swallow / async dispatch 失敗 swallow
- COST_TABLE 各 provider 計算 + 未知 model + NIM 前綴自動 0 + 負數安全
- AI_CALL_LOGGING_ENABLED 開關 + kill-switch 連續失敗
- 6 條告警規則spike/gemini share/error rate/budget/gcp hit/cache+ insights 規則
- 報表 6 段落齊全 + 4096 截斷 + HTML escape + DB fail 路徑
- format helpersfmt_kb/esc/budget_line/trend_line邊界
**通過 ai_call_logger 「DB 失敗永不影響主流程」鐵律**`test_db_failure_does_not_break_main_flow` + `test_async_dispatch_failure_swallowed` 兩條測試直接證明。
**通過「meta 不洩露 prompt 原文」鐵律**`test_meta_does_not_leak_raw_prompt_into_call_state` + `test_set_prompt_hash_truncates_to_12` 兩條測試。
---
## 安全/PII 審計(六大類深審)
| 類別 | 結論 | 證據 |
|---|---|---|
| **A. logger 安全** | ✅ 失敗安全到位 | `_write_to_db` 全 try/except / kill-switch 在連續 10 次失敗觸發 (`_record_failure:80-89`) / `_async_write` 走 daemon thread 不阻塞 |
| **B. PII 保護** | ⚠️ **新發現 chat_id 進 metaH6** | logger 本身只用 `set_prompt_hash` 雜湊;但 4 個 Bot 入口直接灌 chat_id 進 meta — 違反規格 |
| **C. SQL Injection** | ✅ 全參數化 | `_exec_query` 強制走 SQLAlchemy `text(sql), params`7 條報表 SQL 全用 named param |
| **D. HTML escape** | ✅ 對齊既有風格 | `_esc()` 對 `&<>` 三字元與 `telegram_templates._html_escape` 一致;所有 user-controlled (caller/model/error/insight text) 進 HTML 前都 escape |
| **E. 路由 / cron 衝突** | ✅ 23:55 唯一 | 17 條既有 cron 中無 23:5x 區段資源競爭風險低DB query 預估 < 30s |
| **F. 預算 0 / 除 0** | ✅ 全數防護 | 7 處潛在除 0 全部有 `if X else default` 守衛 |
---
## 與既有系統整合風險
### 1. A4 修改 vs Phase 2 A6 即將修改 — **conflict 風險評估**
| 檔案 | A4Phase 1做了什麼 | A6Phase 2將做什麼 | Conflict 風險 |
|---|---|---|---|
| `services/ollama_service.py` | + `get_host_label()` / `OllamaResponse.host` 欄位 / `host=self.host` 4 處 | 預期擴 GCP/111 切換邏輯B2、補 token 欄位M7 | 🟡 中 — 都動同一個 `OllamaResponse` dataclass + `generate()` 主體;建議 A6 先 rebase 再開工 |
| `services/code_review_pipeline_service.py` | 3 處包 log_ai_callhermes/openclaw/elephant | 修補 B3 / 接入 ad-hoc retry | 🟡 中 — 都動 `_hermes_scan` / `_openclaw_assess` 主流程rebase 前先讀 A4 區塊 |
| `services/aider_heal_executor.py` | A4 **未動** | A6 將動 | ✅ 低 — 完全分離 |
| `routes/openclaw_bot_routes.py` | 4 處包 log_ai_callmain/gemini×2/nim | 預期不會碰 | ✅ 低 |
| `services/hermes_analyst_service.py` | 2 處包 log_ai_call + 修 commit 00591c5 殘留 bug | 預期不碰 | ✅ 低 |
| `services/nemoton_dispatcher_service.py` | 1 處包 log_ai_call | 預期不碰 | ✅ 低 |
| `services/openclaw_strategist_service.py` | _call_gemini/_call_nvidia_nim 加 `caller=` 參數 | 預期不碰 | ✅ 低 |
**建議**
- A6 開工前先 `git pull origin main` 拉到 A4 的 commit
- 動 `ollama_service.py` 時優先**新增**而非改既有 dataclass 欄位minimize merge conflict
- 動 `code_review_pipeline_service.py` 時保留現有 `with log_ai_call(...)` 包裝層,僅在内層修補
### 2. `commit 00591c5` 殘留 bug 修復確認
`services/hermes_analyst_service.py:194-200`:原本 commit 00591c5 動到 `except Exception as e:` 區塊時,誤把 `logger.warning` 抹除留下孤立 f-string。本輪 A4 順手修補:
```python
except Exception as e:
# NOTE: 修補 commit 00591c5 殘留的孤立 f-string原 logger.warning 被誤刪)
logger.warning(
f"[Hermes.intent] Ollama 連線失敗,降級規則引擎"
f"model={HERMES_MODEL} error={type(e).__name__}: {e}"
)
_ctx.set_error(f"{type(e).__name__}: {e}")
_ctx.fallback_to_caller('hermes_rule_engine')
return None
```
✅ **已驗證**logger.warning 完整呼叫 + ctx.set_error + fallback_to_caller 三件齊全。原 silent failure 反模式已破。
---
## Phase 2 銜接建議
統帥批准 Phase 2 A6 開工前,建議先 commit Phase 1 的所有變動到 mainA6 才有乾淨 baseline。順序
```bash
git add migrations/024 migrations/025 migrations/026 # A3
git add services/ai_call_logger.py services/token_report_service.py # A4/A5
git add tests/test_ai_call_logger.py tests/test_token_report_service.py # A4/A5 tests
git add services/hermes_analyst_service.py services/nemoton_dispatcher_service.py
git add services/openclaw_strategist_service.py services/code_review_pipeline_service.py
git add services/ollama_service.py routes/openclaw_bot_routes.py
git add run_scheduler.py services/telegram_templates.py
git add docs/phase0_audit_report_20260503.md docs/phase1_db_design_20260503.md
git add docs/phase1_critic_review_20260503.md docs/phase1_final_critic_signoff_20260503.md
git commit -m "[Phase 1] Operation Ollama-First v5.0 觀測層落地 (A3 migration / A4 logger 13 callers / A5 token report)"
```
部署後第一波驗證Phase 2 啟動前):
```sql
-- 1. CHECK constraint 全在
SELECT conname FROM pg_constraint WHERE conrelid='ai_calls'::regclass ORDER BY conname;
-- 2. 種子預算 10 筆
SELECT period, provider, budget_usd, alert_pct FROM ai_call_budgets ORDER BY period, provider NULLS FIRST;
-- 3. logger 寫入煙測A4 接入後第一次 LLM 呼叫應出現)
SELECT caller, provider, model, status, input_tokens, output_tokens, duration_ms
FROM ai_calls ORDER BY called_at DESC LIMIT 20;
-- 4. caller 分布(驗證 13 個白名單值)
SELECT caller, COUNT(*) FROM ai_calls GROUP BY caller ORDER BY 2 DESC;
-- 5. 失敗率(觀察 kill-switch 是否誤觸發)
SELECT status, COUNT(*) FROM ai_calls
WHERE called_at >= NOW() - INTERVAL '24h' GROUP BY status;
```
Phase 2 進度第 1 天觀察點:
- `SELECT count(*) FROM ai_calls;` 應 ≥ 100戰役前審計 34 個呼叫點 / 一日 ~200 calls
- `SELECT count(DISTINCT caller) FROM ai_calls;` 應 ≥ 13
- 23:55 cron 第一次跑完應有 1 筆 `ai_insights WHERE insight_type='daily_token_report'`
---
## NOTE 清單Sign-off 條件)
deploy 後 7 天内由統帥決策處理:
- [ ] **NOTE-1H5**:考慮加 caller 格式 CHECK constraintNOT VALID 不阻既存資料)
- [ ] **NOTE-2H6**4 個 Bot 入口的 `chat_id` 改成 hash 後存Phase 2 第一波 patch
- [ ] **NOTE-3M7**`OllamaResponse` 補 `prompt_tokens/completion_tokens` 欄位 → 修復 `openclaw_bot_main` token=0 黑洞(與 Phase 2 A6 ollama_service 改動合併)
- [ ] **NOTE-4L1**deploy 前手動驗 `git fetch ewoooc && git log ewoooc/main --oneline -- migrations/`
deploy 後 30 天可選優化:
- [ ] **M9** ai_insights confidence 標 1.0 / **M10** HTML tag 截斷修補 / **L5** qwen3:14b 進 COST_TABLE / **L7** 刪 `Decimal` dead import
- [ ] **B1** ai_usage_tracking ORM 對齊真實 schema雙寫 deprecate roadmap與 ADR-028 合併)
---
## Final Sign-off
```
critic-A11 / 2026-05-03 / Phase 1 final closure
Verdict: APPROVED WITH NOTES
Tests: 52/52 PASSED (22 ai_call_logger + 30 token_report)
Findings (本輪新發現): 0 BLOCKER / 2 HIGH (H5/H6) / 4 MEDIUM (M7-M10) / 4 LOW (L5-L8)
Findings (前輪殘留): 1 HIGH (H4 文件) / 1 MEDIUM (M4 解耦) / 1 LOW (L1 統帥手驗)
簽署critic-A11 (Operation Ollama-First v5.0 / Phase 1 sign-off)
```

View File

@@ -0,0 +1,205 @@
# Phase 2 部署驗證劇本ADR-027 真正落地)
> **Date**: 2026-05-03
> **Phase**: Operation Ollama-First v5.0 — Phase 2A6 debugger
> **修補項**: B1 / B2 / B3 / B4 / N2 / N3
> **修改檔**: `config.py` / `services/ollama_service.py` / `services/aider_heal_executor.py` / `services/code_review_pipeline_service.py`
> **新檔**: `tests/test_ollama_resolve.py`13 tests本機已通過
---
## 一、部署前 dry-run本機
### 1.1 語法檢查
```bash
cd "/Users/ooo/Library/Mobile Documents/com~apple~CloudDocs/momo-pro-system"
python3 -m py_compile config.py services/ollama_service.py \
services/aider_heal_executor.py services/code_review_pipeline_service.py \
tests/test_ollama_resolve.py && echo "PYCOMPILE_OK"
```
期望:`PYCOMPILE_OK`(已驗證)
### 1.2 Unit test
```bash
MOMO_ALLOW_INSECURE_CONFIG_FOR_TESTS=true /opt/anaconda3/bin/python3 -m pytest \
tests/test_ollama_resolve.py \
tests/test_phase3f_cleanup_contracts.py \
tests/test_app_startup_contracts.py \
tests/test_ai_call_logger.py \
tests/test_code_review_pipeline_security.py \
tests/test_auto_heal_safety.py -v
```
期望56 passed13 新 + 43 既有)。已驗證。
### 1.3 import 一致性
```bash
MOMO_ALLOW_INSECURE_CONFIG_FOR_TESTS=true /opt/anaconda3/bin/python3 -c "
from config import get_ollama_host, get_hermes_url, get_embedding_host
from services.ollama_service import resolve_ollama_host, mark_unhealthy
print('get_ollama_host =', get_ollama_host())
print('get_hermes_url =', get_hermes_url())
print('get_embedding_host =', get_embedding_host())
print('resolve_ollama_host=', resolve_ollama_host())
"
```
期望(網路通時):四行都印 `http://34.21.145.224:11434`GCP 可達)或 `http://192.168.0.111:11434`GCP 不可達)。
不可出現 `https://ollama.wooo.work/ollama`(舊寫死 URL
---
## 二、部署後驗證SSH 188
### 2.1 容器健康
```bash
ssh wooo@192.168.0.110 "ssh ollama@192.168.0.188 \"\
docker ps --format '{{.Names}} | {{.Status}}' | grep momo-; \
docker exec momo-pro python3 -c 'from config import get_ollama_host; print(get_ollama_host())' 2>&1\""
```
期望:
- `momo-pro | Up`(重啟後新容器)
- 列印的 host 不是 `https://ollama.wooo.work/ollama`
### 2.2 OllamaHost 解析 logB3 HTTP probe 驗證)
```bash
ssh wooo@192.168.0.110 "ssh ollama@192.168.0.188 \"\
docker logs momo-pro --since 10m 2>&1 | grep -E 'OllamaHost' | tail -20\""
```
期望GCP 可達):
```
[OllamaHost] GCP 主機可用,使用 Primary: http://34.21.145.224:11434
```
期望GCP 掛時):
```
[OllamaHost] GCP 主機無法連線,自動切換 Fallback: http://192.168.0.111:11434
```
罕見process 卡死TCP 通但 HTTP 掛):
```
[OllamaHost] GCP HTTP 探測失敗但 TCP 仍通,疑似 process 卡死http://34.21.145.224:11434
[OllamaHost] GCP 主機無法連線,自動切換 Fallback: http://192.168.0.111:11434
```
> 第三種日誌是 **Phase 2 修補後才會看見的新觀測能力**,舊版純 TCP 探測不會印。
### 2.3 mark_unhealthy 觸發B4 驗證)
當 LLM generate 真的失敗時,會看見:
```
[OllamaHost] 主機標記為 unhealthy30s 跳過http://34.21.145.224:11434
```
立刻在下一次任何 ollama 呼叫的 log 看:
```
[OllamaHost] Primary http://34.21.145.224:11434 仍在 unhealthy TTL 內,跳過直接 fallback: http://192.168.0.111:11434
```
### 2.4 AiderHeal OLLAMA_API_BASE 動態化N2 驗證)
下次 AiderHeal 觸發時 grep
```bash
ssh wooo@192.168.0.110 "ssh ollama@192.168.0.188 \"\
docker logs momo-pro --since 30m 2>&1 | grep 'aider_ollama_api_base' | tail -5\""
```
期望:
```
event=aider_ollama_api_base host=http://34.21.145.224:11434
```
GCP 可達時)或 `host=http://192.168.0.111:11434`fallback
**絕不可** 仍顯示 `http://192.168.0.111:11434` 當 GCP 是可達的。
### 2.5 Code Review provider tagN3 驗證)
下次 Code Review pipeline 觸發後:
```bash
ssh wooo@192.168.0.110 "ssh ollama@192.168.0.188 \"\
docker exec momo-postgres psql -U momo -d momo_analytics -c \
\\\"SELECT caller, provider, meta->>'host' AS host \
FROM ai_calls \
WHERE caller = 'code_review_hermes' \
ORDER BY created_at DESC LIMIT 5;\\\"\""
```
期望GCP 通時):
```
caller | provider | host
code_review_hermes | gcp_ollama | http://34.21.145.224:11434
```
絕不可仍標 `ollama_111` 當 host 是 GCP。
---
## 三、模擬故障驗證(選做)
### 3.1 模擬 GCP 不可達 → 5s 內 fallback
在 188 上臨時封鎖 GCP IP
```bash
ssh wooo@192.168.0.110 "ssh ollama@192.168.0.188 \"\
sudo iptables -A OUTPUT -d 34.21.145.224 -j DROP\""
```
立即觸發 sales copyor 任何 LLM 入口),看 log
- 第一次呼叫應 timeout2s 內 _is_reachable 失敗)→ 切 fallback
- 之後 30s 內所有呼叫直接走 fallback
- 30s 後 cache TTL 過期,會重新探測(仍封鎖則繼續 fallback解封後恢復 GCP
恢復:
```bash
ssh wooo@192.168.0.110 "ssh ollama@192.168.0.188 \"\
sudo iptables -D OUTPUT -d 34.21.145.224 -j DROP\""
```
> 此項屬統帥權限debugger 不執行。
---
## 四、回滾 SOP
若部署後出問題,最快回滾:
```bash
git revert <this-commit-sha>
git push origin main
# 等 Gitea CD 自動部署
```
也可以單獨回退 ollama_service.py
```bash
git checkout HEAD~1 -- services/ollama_service.py config.py
```
(其他三檔變更可獨立保留)
---
## 五、commit 草稿
```
[V-New] ADR-027 Phase 2Ollama 主機解析全鏈 lazy + HTTP probe + unhealthy 標記
修補 6 項讓 ADR-027「GCP 優先」真正 100% 落地:
B1 — config.OLLAMA_HOST 改 lazy resolve移除寫死 ollama.wooo.work URL
B2 — config.EMBEDDING_HOST / HERMES_URL 改 lazy避免 import-time freeze
B3 — _is_reachable 改 HTTP probe (/api/version, 2s timeout)TCP 改作觀測點
B4 — 新增 mark_unhealthy()generate / embedding 失敗時標 30scache 失效
N2 — aider_heal_executor.OLLAMA_API_BASE 改 lazy resolve每次 execute 重評估)
N3 — code_review_pipeline_service Hermes scan 改 get_hermes_url() 取代 freeze
新增tests/test_ollama_resolve.py13 tests
變更config.py / services/ollama_service.py /
services/aider_heal_executor.py / services/code_review_pipeline_service.py
驗證56 tests 全綠13 新 + 43 既有 regressionpy_compile 全綠。
驗證劇本docs/phase2_deploy_verify_20260503.md給統帥 SSH 188 跑)。
```

View File

@@ -0,0 +1,404 @@
# Phase 6 Critic Sign-off — Operation Ollama-First v5.0
> **Date**: 2026-05-03
> **Reviewer**: critic-A11Phase 6 文件層收尾,第三輪)
> **Scope**: ADR-028 / ADR-029 / ADR-027 附錄 / docs/adr/README.md
> **基準**: 憲法紅線一(事實驅動,狙擊手精神)
> **任務契約**: 驗證每個具體數字、檔案行號、聲稱的決策都有 Phase 0/1/2/3 報告佐證
---
## Verdict
- [ ] APPROVED — Phase 6 ADR 可 commit
- [ ] APPROVED WITH NOTES — 統帥確認 NOTE 後 commit
- [x] **CONDITIONAL** — 修以下 BLOCKER 後 commitHIGH 可同 commit 內順便修
- [ ] REJECTED
**理由**ADR-028 / ADR-029 在「事實層」有 5 個 BLOCKER 級錯誤行號錯、caller 名虛構、provider 白名單與 DB 不一致、OpenClaw 行數錯、減幅算術不自洽)。這兩份文件一旦 commit 會被未來所有 Phase 引用,事實錯誤會成為「憲法級謬誤」傳承。憲法紅線一不容妥協 — 這幾個數字必須改正後再 merge。
ADR-027 附錄與 README 索引部分基本正確,但附錄 A 引用「寫死 IP 已全面消除」用詞過強aider_heal_executor.py:62 仍有 fallback 字面 IP降為 HIGH。
---
## 事實核驗(逐項)
### A. 程式碼行數
| 聲稱 | ADR 寫 | wc -l 實測 | 差距 | 判定 |
|---|---|---|---|---|
| `services/openclaw_strategist_service.py` | **1831 行**ADR-029:18, 113| **2677 行** | **+846+46%** | 🔴 BLOCKER |
| `services/hermes_analyst_service.py` | **573 行**ADR-029:19| **607 行** | +34+5.9% | 🟠 HIGH |
| 比率 | 4.4× | 4.41× | 湊巧仍對 | ✅ |
| 預估 A10 後 | 1300 行 | — | 但是基準錯,目標 1300 行也失準 | 🔴 連帶 |
**證據**
```
$ wc -l services/openclaw_strategist_service.py services/hermes_analyst_service.py
2677 services/openclaw_strategist_service.py
607 services/hermes_analyst_service.py
```
ADR-029 的 1831 / 573 是直接抄 phase0 audit也錯而非實際數行。狙擊手精神失守。
### B. 場景 file:line 行號
| 場景 | ADR-028 寫 | 實測 | 判定 |
|---|---|---|---|
| #1 MCP L1 Grounding | `mcp_collector_service.py:163-167` | 163-167 是 `for tools in (...)` Gemini 設定區塊 | ✅ 對得上 |
| #2 MCP L2 Grounding | `mcp_collector_service.py:185-186` | 185-186 是 except 塊內的 1.5-flash 重試 | ✅ 對得上 |
| #3 PPT generator | `routes/openclaw_bot_routes.py:2464-2477` | 2469 是 `_call_gemini` def | ✅ 對得上 |
| #4 openclaw_weekly | `services/openclaw_strategist_service.py:759` | **實際在 1340** | 🔴 BLOCKER |
| #4 openclaw_monthly | `services/openclaw_strategist_service.py:1267` | **實際在 1771** | 🔴 BLOCKER |
| #4 openclaw_annual | 「戰略月年報」(無 file:line+ caller 名 `openclaw_annual` | **caller 與 function 都不存在**grep 0 hits| 🔴 BLOCKER虛構 |
| #5 code_review_openclaw | `services/code_review_pipeline_service.py:278-286` | 278-286 是 system/user prompt 字串;實際 `_call_gemini` 在 309 | 🟠 HIGH行號偏移 |
| #6 ea_hitl_prefetch | `services/elephant_alpha_orchestrator.py`(無行號)+ caller 名 `ea_hitl_prefetch` | **caller 不存在**grep 0 hits | 🔴 BLOCKER虛構 caller |
| #7 openclaw_qa_complex_sku | `services/openclaw_strategist_service.py:56` | line 56 是 feature flag 註解caller `openclaw_qa_complex_sku` 不存在grep 0 hits | 🔴 BLOCKER虛構 caller + 行號錯) |
證據:
```
$ grep -rn "ea_hitl_prefetch\|openclaw_qa_complex\|openclaw_annual" services/ routes/
0 hits
```
ADR-028 的「鎖定 Gemini 7 個場景」表格把 7 個 caller 名直接寫入 ADR但其中 3 個(#4 annual / #6 EA HITL / #7 complex SKU**caller 名是憑空編出來的**,至今程式碼從未 emit 這些 caller。等同 ADR 治理規則指向「不存在的東西」。
### C. Provider 白名單一致性
| 來源 | provider 列表 | 數量 |
|---|---|---|
| ADR-028:104-114「Provider 白名單」表格 | `gcp_ollama` / `ollama_secondary` / `ollama_111` / `gemini` / `nim` / `nim_via_elephant` / `openrouter` | 7**不含 claude含 ollama_secondary**|
| ADR-028:114「移除原計畫的 claude provider」聲明 | 7不含 claude | 7 |
| ADR-028:208 Verification V1 期望輸出 | 7不含 claude | 7 |
| 實際 `migrations/024:92-94` `chk_ai_calls_provider` | `gcp_ollama` / `ollama_secondary` / `ollama_111` / `gemini` / `claude` / `nim` / `openrouter` / `nim_via_elephant` | **8含 claude** |
| `services/token_report_service.py:42-50` `_PROVIDER_DISPLAY` | `gcp_ollama` / `ollama_111` / `gemini` / `claude` / `nim` / `openrouter` / `nim_via_elephant` | 7**含 claude不含 ollama_secondary**|
| `migrations/025` budget 種子 monthly 列表 | 7`claude` 但缺 `ollama_secondary` | 7 |
**三處不一致**
1. ADR-028 表格寫含 `ollama_secondary` 不含 `claude`
2. DB CHECK 兩個都包含
3. token_report `_PROVIDER_DISPLAY` 與 budget 種子兩個都缺 `ollama_secondary`,含 `claude`
判定:🔴 BLOCKER。ADR-028 的 Verification V1「期望輸出」實際跑會驗證失敗會多出 `claude`、缺 `ollama_secondary`...都不是 — 8 個對照 7 個直接 mismatch`phase1_final_critic_signoff_20260503.md:26` 也記成「7 個 provider 與 _PROVIDER_DISPLAY 完全一致」— 這是上一輪 critic 的盲區,現在被 ADR-028 沿襲。
### D. OpenClaw / Hermes Token 流量估算
ADR-029 line 23-25 與 line 91-94 的算術:
- 戰前 Gemini ~50M tokens/月、Hermes ~30M tokens/月
- 任務 3/4/5 遷移省 ~12M tokens
- 任務 11 降頻省 ~3M tokens
- 戰後 Gemini ~38M tokens/月line 112
- 減幅 -23%line 112
**算術不自洽**
- 50M (12M + 3M) = **35M**(非 38M
- 50→38 = **-24%**(非 -23%
- 50→35 = **-30%**
三個數字(戰後 38、節省 15、減幅 23至少有一個錯三個都互不對齊。
判定:🔴 BLOCKER。憲法級文件出現自相矛盾的關鍵 KPI 數字。
ADR 第 119 行已誠實標示「上述為 Phase 0 audit 推算Phase 5 報表上線後以 ai_calls 實測值修訂」— 動機可諒解(沒實測),但即便是估算,三個推算值也必須互相對得上。
### E. Meta 自審 6h → 12:00
| 聲稱 | 實際 | 判定 |
|---|---|---|
| `run_scheduler.py:99` 改為每日 12:00 | line 99 `schedule.every().day.at("12:00").do(run_openclaw_meta_analysis_task)` | ✅ 已落地 |
| 月省 ~3M Gemini tokensADR-029:93| `run_scheduler.py:97` 註解寫「~1.875M」 | 🟡 LOW兩處數字不對齊但量級接近 |
| 對應 task = A10 / Phase 7-8ADR-029:104| 註解寫 Phase 4 落地 | 🟠 HIGHA10 標籤對應 Phase 與實際提交時 Phase 不一致)|
### F. 寫死 IP 是否「全面消除」
ADR-027 附錄 A 寫「寫死 IP 已全面消除aider_heal_executor.py:48-49 與 code_review_pipeline_service.py:218-225 兩處 N2/N3 修補)」。
實測:
```
$ grep -rn "192.168.0.111" services/ routes/ | grep -v "OLLAMA_HOST_FALLBACK\|test_\|resolve_ollama_host\|#"
services/aider_heal_executor.py:62: return "http://192.168.0.111:11434" ← 仍有
services/hermes_analyst_service.py:7: 模型hermes3:latest @ HERMES_URL預設 192.168.0.111:11434 ← docstring 仍寫
```
`aider_heal_executor.py:62``_default_ollama_api_base()` 的最後 except 兜底line 60-62技術上是「resolve 失敗才回退到字面 111」不是「import-time 寫死」,但「全面消除」的措辭過強。
判定:🟠 HIGH。建議改為「`import-time` 寫死 IP 已全面消除line 48-49 已改為 lazy resolveline 62 保留 except 兜底字面 IP 作為最終防線)」。
### G. 11.8% AIGenerationHistory 覆蓋率
phase0 audit Section 1.4 line 80-81 寫「4/34 ≈ 11.8%」 → ADR-028 line 19 引用一致 ✅。
### H. Phase 1 / 2 / 3 落地狀態
| Phase | ADR 寫 | 實測 | 判定 |
|---|---|---|---|
| Phase 0 | ✅ 完成 | phase0_audit + phase0_research 都存在 | ✅ |
| Phase 1 | 52/52 tests pass | phase1_final_critic_signoff 確認 | ✅ |
| Phase 2 | 13+43=56 tests pass | phase2_deploy_verify 確認 | ✅ |
| Phase 3 A7 | 已完成feature flag| `OPENCLAW_QA_OLLAMA_FIRST` env 在 openclaw_strategist_service.py:51, 61, 162-163, 259 出現,預設 false | ✅ |
| migration 024/025/026 | 存在 | `migrations/024_create_ai_calls_table.sql` / `025_create_mcp_calls_and_budgets.sql` / `026_add_embedding_signature.sql` | ✅ |
| Meta 12:00 | run_scheduler.py:99 | 確認 | ✅ |
---
## Findings
### BLOCKER事實錯誤必須改
#### B1. ADR-029 OpenClaw 行數錯 846 行(+46%
- **位置**`docs/adr/ADR-029-hermes-first-twin-tower.md:18, 113`
- **錯誤**:寫 `services/openclaw_strategist_service.py ≈ 1831 行`
- **實測**`wc -l = 2677 行`
- **影響**
- line 18 的「失衡證據」(戰前 1831失真但比率 4.4× 湊巧仍接近真實 4.41×(仍在 4× 量級)
- line 113 的「預估 1300 行A10 後)」基準錯誤 → 戰後行數要 -29% 應是 ~1900 行才合理;若仍要砍到 1300是 -51%(戰前 2677 → 1300是更激進的目標但 ADR 沒揭露
- 量化效益表的 OpenClaw 程式碼瘦身欄位失準
- **建議修法**
- 把 1831 改 2677
- 重算「-29% 後 ~1900 行」或「若仍鎖定 1300 行則應改寫為 -51%(更大重構工程)」
- line 142 的「OpenClaw 從 1831 行降至 ~1300 行A10」同步修
#### B2. ADR-028 場景 #4 行號錯759/1267 vs 1340/1771
- **位置**`docs/adr/ADR-028-llm-routing-unified-principles.md:75`
- **錯誤**「openclaw_weekly / openclaw_monthly / openclaw_annual」location 寫 `services/openclaw_strategist_service.py:759, 1267, 戰略月年報`
- **實測**
- `caller="openclaw_weekly"` 在 line 1340
- `caller="openclaw_monthly"` 在 line 1771
- `caller="openclaw_annual"` **0 hits**(不存在)
- **影響**:未來新工程師看 ADR 找 759 line 會找到 `_legacy_gemini_first_qa` 內部,誤判 caller 對應位置annual report 根本沒實作但 ADR 列為「鎖定場景」
- **建議修法**
- 759 → 13401267 → 1771
- `openclaw_annual` 從鎖定場景表移除(或改為「待實作」並引述 Phase X 計畫)
#### B3. ADR-028 場景 #6 / #7 caller 名虛構
- **位置**`docs/adr/ADR-028-llm-routing-unified-principles.md:77-78`
- **錯誤**
- 場景 #6 caller `ea_hitl_prefetch` — grep 0 hits程式碼從未 emit 此 caller
- 場景 #7 caller `openclaw_qa_complex_sku` — grep 0 hits同上
- **實測**
```
$ grep -rn "ea_hitl_prefetch\|openclaw_qa_complex" services/ routes/
(無輸出)
```
- **影響**ADR 把治理規則繫於不存在的 callerDB token report `WHERE caller='ea_hitl_prefetch'` 永遠 0 筆Phase 5 預算告警會誤判
- **建議修法**
- 若是「規劃中」,標示 `(規劃中Phase X 引入)`
- 若是「已存在但 caller 名不同」,改為實際 caller例如 EA HITL 預跑可能走 `hermes_intent` / `hermes_analyst`
- line 78 的 `services/openclaw_strategist_service.py:56` 不是 caller 而是 feature flag 註解,行號需重指
#### B4. ADR-028 Provider 白名單與 DB CHECK 不一致
- **位置**
- `docs/adr/ADR-028-llm-routing-unified-principles.md:104-114`(白名單表)
- `docs/adr/ADR-028-llm-routing-unified-principles.md:114`(移除 claude 聲明)
- `docs/adr/ADR-028-llm-routing-unified-principles.md:208`V1 期望輸出)
- **錯誤**ADR 寫 7 個 provider含 ollama_secondary不含 claude
- **實測**
- `migrations/024_create_ai_calls_table.sql:92-94` 是 **8 個**(含 claude 與 ollama_secondary
- `services/token_report_service.py:42-50` `_PROVIDER_DISPLAY` 是 7 個(**含 claude不含 ollama_secondary**
- `migrations/025` 預算種子 monthly 是 7 個(含 claude缺 ollama_secondary
- **影響**
- Verification V1 SQL 跑出來會與「期望」對不上 → 部署驗證會誤判 FAIL
- 「移除 claude」是空話 — DB 並未移除
- `ollama_secondary` 在 DB 接受但無任何程式碼會 emit → SELECT 永遠 0 筆 → Phase 5 三主機級聯可觀測性失真
- **建議修法**(三選一):
- 路線 AADR-028 改為「8 provider含 claude新增程式碼 emit `ollama_secondary` 標籤patch `code_review_pipeline_service.py:230` 與其他 Ollama caller根據 resolve 結果動態決定)
- 路線 B實際下一個 migration 移除 claude並在 _PROVIDER_DISPLAY 加 ollama_secondary讓三層真正一致
- 路線 CADR-028 加一段「Schema vs ADR 差異」誠實揭露Phase X 統一
#### B5. ADR-029 Token 流量算術不自洽38M vs 35M vs -23%
- **位置**`docs/adr/ADR-029-hermes-first-twin-tower.md:23-25, 91-94, 112`
- **錯誤**
- 戰前 50M → 任務 3/4/5 省 12M、任務 11 省 3M = 共省 15M → 戰後應 35M
- 但 line 112 寫戰後 38M、減幅 -23%
- 50→38 = -24%(非 -23%50→35 = -30%
- **影響**:戰役 v5.0 KPI「Gemini 月支出 -23%」是 README 索引line 53的明牌數字之間互不對齊讓未來無法驗收
- **建議修法**
- 三個數字選一個錨定,其他重算:
- 錨定 -23% → 戰後 38.5M → 節省 11.5Mtask 3/4/5/11 拆分需重估)
- 錨定節省 15M → 戰後 35M → 減幅 -30%README 索引也要改)
- 或加註腳「戰後 token 估算為四捨五入區間,實測誤差 ±5M」誠實揭露不確定性
### HIGH建議改不一定阻 commit
#### H1. Hermes 行數差 +5.9%
- 位置ADR-029:19
- 寫 573 vs 實測 607
- 改為「607 行」即可
#### H2. ADR-027 附錄 A「寫死 IP 全面消除」措辭過強
- 位置ADR-027 附錄 A 段尾
- 實際 `aider_heal_executor.py:62` 仍有字面 `return "http://192.168.0.111:11434"`(在 except 兜底)
- 建議改為「import-time 寫死已消除except 兜底保留 111 字面 IP 作為最終防線」
#### H3. ADR-028 場景 #5 行號偏移
- 位置ADR-028:76
- 寫 `code_review_pipeline_service.py:278-286`,實際 278-286 是 prompt 字串;`_call_gemini` 在 line 309
- 建議改 `:278-310`(涵蓋整個 Gemini 呼叫塊)或 `:309`
#### H4. ADR-028 caller 白名單列了 30+ 個但實際 emit 僅 ~16 個
- 位置ADR-028:122-138
- 實際 `grep "caller=" services/ routes/` 唯一 16 個(已驗證上方)
- 列表混雜了「已實作」與「規劃中」沒區分標示
- 建議:在每個 caller 後標示 `[A4 已落地]` / `[Phase X 規劃中]`
#### H5. `ollama_secondary` provider 沒有任何 caller emit
- 位置ADR-028:107白名單條目
- 程式碼層 0 hits — 三主機級聯實作只區分 GCPgcp_ollamavs 111ollama_111Primary/Secondary 在程式中不區分
- 建議:要嘛在 `services/ollama_service.resolve_ollama_host()` 與所有 caller 加上「根據 selected host 決定 provider tag」要嘛把 `ollama_secondary` 從白名單移除直到實作完成
#### H6. ADR-029 Phase 標籤錯亂
- 位置ADR-029:104
- 寫「A10 對應 Phase 7-8」
- run_scheduler.py:97 註解寫「Phase 4 降頻」
- ADR-028 Migration Plan line 248 也寫「Phase 7-8 OpenClaw 程式瘦身A10
- 不一致;建議在文件層統一定義 A10 的 Phase 對應
### MEDIUM
#### M1. ADR-029 第 5 行作者列「Codex / A12 planner」但戰役組織圖中 A12 是 critic不是 planner
- 位置ADR-029:6 / ADR-028:6
- planner 角色是 A8從上下文推斷但 ADR 寫 A12
- 不影響事實,但角色標籤需與 v5.0 戰役組織圖核對
#### M2. ADR-028 line 156 「Gemini 2.5 Flash vs qwen3:14b 估差 10-20%」引用 phase0_research_report Section 1但 phase0 報告 Section 1 結論是「黃燈,需 50 題黃金集 A/B 才能定論」,沒給出 10-20% 的硬數字
- 位置ADR-028:156
- phase0_research line 30-33 寫「推估 10-20%」是未驗證的推估ADR 直接當事實引用
- 建議改為「**推估** 10-20%(待 Phase 4 黃金集 A/B 確認)」
#### M3. ADR-027 附錄 A 引用「services/code_review_pipeline_service.py:218-225」但實際 218-225 是 prompt 字串
- 位置ADR-027 line 65
- 實際 `_call_gemini` 與 hermes scan 在 line 230 後
- 行號偏移phase0 audit 也錯(同樣的 inheritance 錯誤)
### LOW
#### L1. ADR-028:75 寫「`戰略月年報`」中文字摻在 file:line 列,破壞表格格式
- 位置ADR-028:75
- 應改為「(戰略月/年報function 待實作)」或拆兩行
#### L2. ADR-028 Migration Plan 列了 Phase 0-12 但 Phase 11 / 12 與其他 ADR如 ADR-026 收尾路線圖)的 Phase 編號可能重疊
- 跨 ADR 的 Phase 編號需要統一索引避免混淆
- 不阻 commit
#### L3. ADR-029 line 4 沒有 Author 欄位ADR-028 有)
- 風格不一致
---
## ADR 引用一致性
| ADR-028 / 029 引用 | 實際內容 | 判定 |
|---|---|---|
| ADR-002 pgvector 唯一向量庫 | 確實存在未被破壞memory-mcp 在 phase0 也標 🔴 不採用)| ✅ |
| ADR-003 Hermes embedding 本地化 | 存在 | ✅ |
| ADR-004 NemoTron fallback chain | 存在ADR-028 引「NIM 80 calls/day」與 ADR-004 一致 | ✅ |
| ADR-008 部署實機驗證 | 存在 | ✅ |
| ADR-013 AIOps AutoHeal | 存在 | ✅ |
| ADR-018 四 Agent 控制面 | 存在ADR-029 「ADR-018 已定四 Agent 角色,但未量化誰處理高頻」描述準確 | ✅ |
| ADR-019 Telegram Agentic Layer | 存在ADR-029 line 30 描述「openclaw_decide() 把所有用戶輸入導向」與 ADR-019 一致 | ✅ |
| ADR-021 EA HITL pre-fetch | 存在;但 ADR-028 場景 #6 caller 名與 ADR-021 內 Hermes 預跑實作不對應B3| 🔴 連帶 |
| ADR-027 「Supersedes: 無(補述 ADR-027非取代」 | 措辭合理,因 ADR-027 仍存在且新增了附錄 | ✅ |
| `migrations/024:88-91` provider CHECK | 實際 line 92-94包含 8 個 provider含 claude| 🔴 B4 |
| `migrations/024:104-109` meta/error 大小 | 已驗證(與 phase1 critic H2 一致)| ✅ |
| phase0_audit Section 1.4 11.8% | 一致 | ✅ |
| phase1_final_critic_signoff H5/H6 | 一致 | ✅ |
---
## 鎖定 Gemini 7 場景驗證LOCKED-GEMINI 註解 vs ADR-028
| # | LOCKED-GEMINI 程式碼註解 | ADR-028 場景 | 一致? |
|---|---|---|---|
| #1 | `services/mcp_collector_service.py:32` LOCKED-GEMINI: MCP 即時情報需 Google Search Grounding | 場景 #1 MCP L1 Grounding | ✅ |
| #2 | (無獨立註解,與 #1 同)| 場景 #2 MCP L2 Grounding | ✅(共享)|
| #3 | `routes/openclaw_bot_routes.py:98` LOCKED-GEMINI: PPT 簡報文案需長 context + 繁中商業敘事 | 場景 #3 PPT generator | ✅ |
| #4 | `services/openclaw_strategist_service.py:40` LOCKED-GEMINI: 週/月/年報需長 context + 繁中商業文體 | 場景 #4 weekly/monthly/annual | 🟠annual caller 不存在 — B3|
| #5 | `services/code_review_pipeline_service.py:46` LOCKED-GEMINI: Code Review 全 repo diff 可達 100K+ tokens | 場景 #5 code_review_openclaw | ✅ |
| #6 | `services/elephant_alpha_orchestrator.py:88` LOCKED-GEMINI: EA HITL 戰略決策影響統帥行動 | 場景 #6 ea_hitl_prefetch | 🟠caller 名與註解中的 "AgentCapability" 模型 `gemini-2.0-flash` 對不上 ADR 寫的 `gemini-2.5-flash`|
| #7 | (無獨立註解)| 場景 #7 openclaw_qa_complex_sku | 🔴caller 完全不存在 — B3|
**註解 vs ADR 模型不一致**
- ADR-028 場景 #6 寫 `gemini-2.5-flash`
- `services/elephant_alpha_orchestrator.py:91` AgentCapability 寫 `model="gemini-2.0-flash"`
- 哪個是真的?需校對
---
## 與既有 ADR 衝突grep 結果)
```
$ grep -rn "ADR-028\|ADR-029" docs/adr/
(除 ADR-027 / 028 / 029 / README 自身互引以外,其他 ADR-001~026 均無提及)
```
✅ 既有 ADR 沒有提到 028/029所以沒有外部引用衝突。
✅ ADR-002pgvector 唯一phase0 audit Section 2 已標 memory-mcp 🔴 不採用ADR-028 沒破壞此決策。
✅ ADR-018四 Agent 控制面ADR-029 是「補述」而非取代,措辭合理。
✅ ADR-027附錄正式承接Supersedes 標示「無(補述)」措辭正確。
---
## 核准條件CONDITIONAL → APPROVED 的必修清單)
- [ ] **B1 修**ADR-029 line 18, 113, 142 把 `1831` 改 `2677`A10 預估目標重算(建議 -29% → 1900 或維持 1300 但重標 -51%
- [ ] **B2 修**ADR-028 line 75 行號 759 → 1340、1267 → 1771
- [ ] **B3 修**ADR-028 場景 #4 移除 annual或標「規劃中」場景 #6 改用實際存在的 caller 名(如 `hermes_analyst` 或備註「Phase X 引入」);場景 #7 同
- [ ] **B4 修**ADR-028 Provider 白名單表格與 V1 期望輸出與 DB CHECK / token_report `_PROVIDER_DISPLAY` 對齊(含 claude、處理 ollama_secondary 缺口)
- [ ] **B5 修**ADR-029 line 23-25, 112 三個數字(戰前 50M / 戰後 38M / 減幅 -23% / 任務節省 12M+3M對齊建議錨定 README 索引「-23%」並回算其他兩個
修這 5 個 BLOCKER 後可 commit。HIGH 可同 commit 內順便修,不修也不阻 commit但會留入 Phase 7+ 技術債)。
---
## Sign-off
```
critic-A11 / 2026-05-03 / Phase 6 / 第三輪審查
Verdict: CONDITIONAL5 BLOCKER 待修)
Files Reviewed:
docs/adr/ADR-028-llm-routing-unified-principles.md (269 lines)
docs/adr/ADR-029-hermes-first-twin-tower.md (222 lines)
docs/adr/ADR-027-primary-ollama-on-gcp.md (114 lines, 含附錄)
docs/adr/README.md (60 lines)
Cross-checked Against:
docs/phase0_audit_report_20260503.md (262 lines)
docs/phase0_research_report_20260503.md (231 lines)
docs/phase1_db_design_20260503.md (315 lines)
docs/phase1_final_critic_signoff_20260503.md (317 lines)
docs/phase2_deploy_verify_20260503.md (205 lines)
migrations/024_create_ai_calls_table.sql
migrations/025_create_mcp_calls_and_budgets.sql
services/openclaw_strategist_service.py (2677 lines, wc -l)
services/hermes_analyst_service.py (607 lines, wc -l)
services/ollama_service.py (resolve_ollama_host + mark_unhealthy)
services/ai_call_logger.py
services/token_report_service.py (_PROVIDER_DISPLAY)
services/code_review_pipeline_service.py (LOCKED-GEMINI / provider tag)
services/mcp_collector_service.py (LOCKED-GEMINI)
services/elephant_alpha_orchestrator.py (LOCKED-GEMINI)
services/aider_heal_executor.py (lazy resolve / 兜底字面 IP)
routes/openclaw_bot_routes.py (LOCKED-GEMINI / caller emit / PPT _call_gemini)
run_scheduler.py:99 (Meta 12:00)
Discipline: 憲法紅線一(事實驅動 / 狙擊手精神)— 嚴格批評;
不修補 ADR僅標 BLOCKER / HIGH / MEDIUM / LOW
所有 finding 附 file:line 並對照 phase 報告。
```

View File

@@ -0,0 +1,202 @@
# AiderHeal 110 主機部署 SOPADR-020
> 解決 2026-05-03 發現的 AiderHeal 100% no-op 根因110 主機上 `AIDER_REPO_PATH` (`/home/wooo/ewoooc`) **不存在**,所有 `cd` 立刻失敗,`|| true` 吞掉錯誤後整條 pipeline 走完卻 0 次 push。
>
> 本 SOP 設定一次後永久生效,需統帥手動執行(牽涉 SSH key 部署 + Gitea push 權限驗證)。
---
## 前置確認
| # | 檢查項 | 命令 |
|---|--------|------|
| 1 | 110 主機可達 | `ssh wooo@192.168.0.110 hostname` |
| 2 | 110 上是否已有 `~/.ssh/autoheal_id_ed25519` | `ssh wooo@192.168.0.110 'ls -la ~/.ssh/autoheal*'` |
| 3 | 188 容器內 `config/autoheal_id_ed25519` 是否存在 | `ssh ollama@192.168.0.188 'ls -la /home/ollama/momo-pro-system/config/autoheal*'` |
| 4 | Gitea 上該 ssh key 是否已加為 deploy keywrite 權限)| Gitea → wooo/ewoooc → Settings → Deploy Keys |
**若 #2 #3 都 OK 且 #4 已加** → 直接跳到「步驟 2 clone repo」
**若 #2 缺 key** → 走「步驟 1 部署 SSH Key」
**若 #4 沒加** → 走「步驟 3 加 Gitea Deploy Key」
---
## 步驟 1部署 SSH Key 到 110 主機
容器內已有的 key 同步到 110作為 110 push 回 Gitea 的身份。
```bash
# 從 188 取出私鑰container mount 點)
ssh ollama@192.168.0.188 'cat /home/ollama/momo-pro-system/config/autoheal_id_ed25519' \
| ssh wooo@192.168.0.110 'umask 077 && cat > ~/.ssh/autoheal_id_ed25519'
# 取公鑰
ssh ollama@192.168.0.188 'cat /home/ollama/momo-pro-system/config/autoheal_id_ed25519.pub' \
| ssh wooo@192.168.0.110 'cat > ~/.ssh/autoheal_id_ed25519.pub'
# 設權限
ssh wooo@192.168.0.110 'chmod 600 ~/.ssh/autoheal_id_ed25519 && chmod 644 ~/.ssh/autoheal_id_ed25519.pub'
# 在 ~/.ssh/config 加 host alias 讓 git 自動用此 key
ssh wooo@192.168.0.110 'cat >> ~/.ssh/config << "EOF"
Host gitea-autoheal
HostName 192.168.0.110
Port 3022
User git
IdentityFile ~/.ssh/autoheal_id_ed25519
IdentitiesOnly yes
EOF
chmod 600 ~/.ssh/config'
```
> **Port 3022 確認**:用 `ssh wooo@192.168.0.110 'docker ps | grep gitea'` 看 Gitea SSH port預設 3022 但可能不同。
---
## 步驟 2在 110 上 clone repo 到 `/home/wooo/ewoooc`(直接 SSH clone
> 注意:**從一開始就用 SSH clone**,避免 HTTP clone 在 private repo 卡帳密 prompt + 跟步驟 1 部署的 key 不關聯。先確認 Gitea SSH port預設 3022 但可能被改):
>
> ```bash
> ssh wooo@192.168.0.110 'docker ps --format "{{.Ports}}" | grep gitea'
> ```
>
> 從輸出找到 `0.0.0.0:NNN->22/tcp` 的 NNN 即為 Gitea SSH port。下方用 3022 為例,**請依實況替換**。
```bash
ssh wooo@192.168.0.110 << 'EOF'
set -e
cd ~
# 防呆:如果 ewoooc 已存在但不是 git repo可能舊垃圾先備份
if [ -d ewoooc ] && [ ! -d ewoooc/.git ]; then
mv ewoooc ewoooc.bak.$(date +%s)
fi
# 直接 SSH clone複用步驟 1 部署的 key + ~/.ssh/config 的 gitea-autoheal alias
if [ ! -d ewoooc/.git ]; then
git clone gitea-autoheal:wooo/ewoooc.git ewoooc
fi
cd ewoooc
# 設 git identity 讓 AiderHeal commit 有可識別作者
git config user.name "AiderHeal"
git config user.email "autoheal@wooo.work"
# 確認 remote 走 SSHgitea-autoheal alias 自帶正確 port + key
git remote -v
git log --oneline -3
EOF
```
驗證:應印出 `origin gitea-autoheal:wooo/ewoooc.git`fetch+push 兩行)和最近 3 個 commit。
> **若 clone 失敗報 `Permission denied (publickey)`**:步驟 3 的 Gitea Deploy Key 還沒加或沒勾 write access先回去處理步驟 3。
---
## 步驟 3在 Gitea 加 Deploy Key若 #4 沒加)
1. 取公鑰:
```bash
ssh wooo@192.168.0.110 'cat ~/.ssh/autoheal_id_ed25519.pub'
```
2. Gitea Web UI
- 開 `http://192.168.0.110:3001/wooo/ewoooc/settings/keys`
- Add Deploy Key
- Title: `AiderHeal 110 host`
- Key: 貼上 #1 的公鑰
- **勾選 `Allow write access`**(必要!否則只能 fetch 不能 push
- Add Key
---
## 步驟 4端到端驗證
### 4a. 110 上手動測試 push 鏈
```bash
ssh wooo@192.168.0.110 << 'EOF'
cd ~/ewoooc
git fetch origin main
git status
EOF
```
預期:`fetch` 不報錯,`status` 顯示 `Your branch is up to date`。
### 4b. 從 188 容器測試 SSH 鏈(模擬 AiderHeal preflight
> 早期版本曾用 `docker exec ... bash -c "ssh ... \"...\""` 三層引號,內層雙引號會被中層吃掉,導致 `&& echo PREFLIGHT_OK` 變成本地 echo 而非 remote echo —— **永遠 false positive**。改用 heredoc + 單引號嵌套保護:
```bash
ssh ollama@192.168.0.188 << 'OUTER'
docker exec momo-pro-system bash -c '
ssh -i /app/config/autoheal_id_ed25519 \
-o StrictHostKeyChecking=no \
wooo@192.168.0.110 "test -d /home/wooo/ewoooc/.git && echo PREFLIGHT_OK"
'
OUTER
```
預期輸出:`PREFLIGHT_OK`**從遠端 110 印出**,非本地)。
驗證真假:故意把 path 寫錯一個字母,應該 **0 輸出**(不該印 PREFLIGHT_OK
### 4c. 觸發 AiderHeal pipeline 觀察
任意推一個會被 Hermes 找到 finding 的 commit或統帥 push 一個下次自然有 finding 的 commit等 2 分鐘後查:
```bash
# 看是否有 AiderHeal 簽名的新 commit
git fetch origin main && git log --pretty='%h | %an | %s' origin/main -5
```
預期:看到 author 是 `AiderHeal` 或 commit message 開頭 `fix(autoheal):` 的新 commit。
### 4d. 看容器 log
```bash
ssh ollama@192.168.0.188 'docker logs momo-pro-system --since 10m 2>&1 | grep -E "event=(heal_start|aider_exec|push_ok|preflight_failed|setup_failed)"'
```
預期:`event=heal_start` → `event=aider_exec`(停 1060s→ `event=push_ok` 連貫出現,**不應**看到 `event=preflight_failed`。
---
## 故障排除
| 症狀 | 可能原因 | 排查 |
|------|---------|------|
| `event=preflight_failed` | 110 上 `~/ewoooc` 不存在 / 不是 git repo | 重跑步驟 2 |
| `event=setup_failed` 顯示 `Permission denied (publickey)` | Gitea deploy key 未加 / write 權限沒勾 | 檢查步驟 3 |
| `event=push_failed` 顯示 `remote: hook declined` | Gitea 設 protected branch | 在 Gitea 把 main 從 protected 移除(或加 deploy key 為例外)|
| `event=no_diff` 但 aider 確實看到問題 | aider 模型品質不佳qwen2.5-coder:7b 太小)| 改 `AIDER_MODEL` env例如 `ollama/deepseek-coder-v2:16b`;需 110 上有對應 model |
| `event=diff_too_large` 連續發生 | finding 牽涉檔案 > 50 行修改 | 調 `AIDER_MAX_DIFF_LINES` env但建議保留 50 作 ADR-020 安全網 |
---
## 安全護欄回顧ADR-020
| L | 機制 | 觸發點 |
|---|------|-------|
| L0 | preflight 路徑檢查 | `aider_heal_executor.py:execute_code_fix` 白名單通過後 |
| L1 | 檔案白名單 `^(services\|routes\|database)/(?:[a-zA-Z0-9_]+/)*[a-zA-Z0-9_]+\.py$`,允許子目錄但不允許 `tests/` | `ALLOWED_FILE_PATTERN` |
| L2 | diff > 50 行拒絕 push | `AIDER_MAX_DIFF_LINES` |
| L3 | 每小時最多 5 次 CODE_FIX | `_enforce_rate_limit` |
| L4 | health check 失敗自動 git revert | `_revert_last_commit` |
| L5 | Telegram 通知(成功/失敗/回滾)| `_notify_telegram` → EventRouter |
主開關:`CODE_REVIEW_AUTO_FIX_ENABLED=false`docker-compose env即時切斷整條鏈。
---
## 完成後更新
- [ ] 110 上 `~/ewoooc` 存在且 `git remote -v` 顯示走 SSH push
- [ ] Gitea deploy key 已加write access 勾選
- [ ] 步驟 4b 印出 `PREFLIGHT_OK`
- [ ] 至少一次自然觸發 AiderHeal 後看到 `fix(autoheal):` commit
- [ ] 通知 Claude 把 memory `feedback_code_review_autoheal.md` 的「待觀察」段刪掉,標記 AiderHeal 執行層也驗證完成

View File

@@ -93,7 +93,7 @@ def post_fork(server, worker):
def post_worker_init(worker):
"""Warm the expensive dashboard cache after each worker is ready."""
"""Load the shared dashboard cache in every worker before user traffic."""
enabled = os.getenv("DASHBOARD_PREWARM_ON_WORKER_INIT", "1").lower()
if enabled in {"0", "false", "no"}:
return
@@ -102,8 +102,10 @@ def post_worker_init(worker):
try:
from routes.dashboard_routes import warm_full_dashboard_cache
warm_full_dashboard_cache(reason=f"gunicorn-worker-{worker.pid}")
from routes.edm_routes import warm_promo_dashboard_cache
warm_promo_dashboard_cache(reason=f"gunicorn-worker-{worker.pid}")
except Exception as exc:
worker.log.warning("Dashboard cache prewarm failed in worker %s: %s", worker.pid, exc)
worker.log.warning("Dashboard/promo cache prewarm failed in worker %s: %s", worker.pid, exc)
thread = threading.Thread(
target=_warm_dashboard_cache,

View File

@@ -2,7 +2,7 @@
# WOOO TECH - Momo Pro System
# Kubernetes Secrets
# =============================================================================
# 注意:此檔案包含敏感資訊,請勿提交到 Git
# 注意:此檔案僅允許占位符,實際敏感資訊請用 kubectl create secret 或外部 secret manager 注入
# 使用方式kubectl apply -f 03-secrets.yaml -n momo
# =============================================================================
apiVersion: v1
@@ -13,24 +13,24 @@ metadata:
type: Opaque
stringData:
# 資料庫
DATABASE_URL: "postgresql://momo:wooo_pg_2026@momo-postgres:5432/momo_analytics"
POSTGRES_PASSWORD: "wooo_pg_2026"
DATABASE_URL: "postgresql://<POSTGRES_USER>:<POSTGRES_PASSWORD>@momo-postgres:5432/momo_analytics"
POSTGRES_PASSWORD: "<POSTGRES_PASSWORD>"
# Flask
SECRET_KEY: "your_flask_secret_key"
LOGIN_PASSWORD: "0936223270"
SECRET_KEY: "<SECRET_KEY>"
LOGIN_PASSWORD: "<LOGIN_PASSWORD>"
# Email
EMAIL_HOST_PASSWORD: "nvvnjpreldxzzas"
EMAIL_HOST_PASSWORD: "<EMAIL_HOST_PASSWORD>"
# Telegram
TELEGRAM_BOT_TOKEN: "8075645931:AAH-EGKMo8ZC4QJs-Nc1_0s92xHrGdQvdpg"
TELEGRAM_BOT_TOKEN: "<TELEGRAM_BOT_TOKEN>"
# LINE
LINE_CHANNEL_ACCESS_TOKEN: "nD6MSXjB2FyB111zpT6Yik5B275mi6olHjjf94VnqN1ljUcqzcA7KtSSslxsOCEG6pERzmidNJFdzol6h+9V+t1x3j4Q8ljAacqC+i0627RuwbkiLxoHTJ/9HbIdehhoSJoeuNJHLraE721iDDfIuQdB04t89/1O/w1cDnyilFU="
LINE_CHANNEL_ACCESS_TOKEN: "<LINE_CHANNEL_ACCESS_TOKEN>"
# Google Gemini AI
GEMINI_API_KEY: "AIzaSyCqv7TY2iTGi2wa91d2irwH08VYXjT9YUk"
GEMINI_API_KEY: "<GEMINI_API_KEY>"
# YouTube API (趨勢爬蟲)
YOUTUBE_API_KEY: "AIzaSyBA9n7-rYIQVMq8rSF7kz486avBAfFzJ0s"
YOUTUBE_API_KEY: "<YOUTUBE_API_KEY>"

View File

@@ -11,21 +11,21 @@ metadata:
type: Opaque
stringData:
# PostgreSQL
POSTGRES_USER: "momo"
POSTGRES_PASSWORD: "wooo_pg_2026"
POSTGRES_USER: "<POSTGRES_USER>"
POSTGRES_PASSWORD: "<POSTGRES_PASSWORD>"
# Telegram Bot
TELEGRAM_BOT_TOKEN: "8075645931:AAH-EGKMo8ZC4QJs-Nc1_0s92xHrGdQvdpg"
TELEGRAM_CHAT_ID: "5619078117"
TELEGRAM_BOT_TOKEN: "<TELEGRAM_BOT_TOKEN>"
TELEGRAM_CHAT_ID: "<TELEGRAM_CHAT_ID>"
# LINE Notify
LINE_NOTIFY_TOKEN: "nD6MSXjB2FyB111zpT6Yik5B275mi6olHjjf94VnqN1ljUcqzcA7KtSSslxsOCEG6pERzmidNJFdzol6h+9V+t1x3j4Q8ljAacqC+i0627RuwbkiLxoHTJ/9HbIdehhoSJoeuNJHLraE721iDDfIuQdB04t89/1O/w1cDnyilFU="
LINE_NOTIFY_TOKEN: "<LINE_NOTIFY_TOKEN>"
# Gemini AI
GEMINI_API_KEY: "AIzaSyCqv7TY2iTGi2wa91d2irwH08VYXjT9YUk"
GEMINI_API_KEY: "<GEMINI_API_KEY>"
# Ollama AI
OLLAMA_API_KEY: "0df8b4f247a4497998248f013ce92a17.vqSWDEK0RppTZIwcdT-ei-Sz"
OLLAMA_API_KEY: "<OLLAMA_API_KEY>"
# App Password
APP_PASSWORD: "0936223270"
APP_PASSWORD: "<APP_PASSWORD>"

View File

@@ -43,9 +43,12 @@ data:
PASSWORD_REQUIRE_DIGIT: "false"
PASSWORD_REQUIRE_SPECIAL: "false"
# Ollama AI 服務
OLLAMA_HOST: "http://192.168.0.188:11434"
OLLAMA_MODEL: "llama3:70b-instruct-q2_K"
# Ollama AI 服務ADR-027 三主機級聯GCP-A → GCP-B → 111
# 已架設 Nginx Proxy (110:11435/11436) 轉發至 GCP解決 K8s 內網無法直連 GCP 11434 的問題。
OLLAMA_HOST_PRIMARY: "http://192.168.0.110:11435"
OLLAMA_HOST_SECONDARY: "http://192.168.0.110:11436"
OLLAMA_HOST_FALLBACK: "http://192.168.0.111:11434"
OLLAMA_MODEL: "qwen3:8b"
# Google Gemini AI 服務
# GEMINI_API_KEY: 請在 K8s Secret 中設定

View File

@@ -1,8 +1,10 @@
apiVersion: v1
data:
google_credentials.json: eyJpbnN0YWxsZWQiOnsiY2xpZW50X2lkIjoiMTMyODIzMDc5MzI2LWg5Y3ZqNWVhaGlnbThocDlxMGI3dDVyazc3Ymh1M2dwLmFwcHMuZ29vZ2xldXNlcmNvbnRlbnQuY29tIiwicHJvamVjdF9pZCI6Indvb28tNDgxMjA0IiwiYXV0aF91cmkiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20vby9vYXV0aDIvYXV0aCIsInRva2VuX3VyaSI6Imh0dHBzOi8vb2F1dGgyLmdvb2dsZWFwaXMuY29tL3Rva2VuIiwiYXV0aF9wcm92aWRlcl94NTA5X2NlcnRfdXJsIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vb2F1dGgyL3YxL2NlcnRzIiwiY2xpZW50X3NlY3JldCI6IkdPQ1NQWC1PSHJRckdkN0pkalN2RkdoUkhXckNfUTFvcUxmIiwicmVkaXJlY3RfdXJpcyI6WyJodHRwOi8vbG9jYWxob3N0Il19fQ==
google_token.pickle: gASV8gMAAAAAAACMGWdvb2dsZS5vYXV0aDIuY3JlZGVudGlhbHOUjAtDcmVkZW50aWFsc5STlCmBlH2UKIwFdG9rZW6UjP55YTI5LmEwQVVNV2dfTGdqc0x5S0dUZXRIcWRlTXY1eHdWUTlhNU1tVy1FMVVrdzNSeUV2MWFacnhCWThKckhlR19HQ2NnQVV4RkpJX0taLTdnd2gtZ3p6bzNRdGpoLXBVdDdQWndyWW5QVzI1RGhBTlFOWVJGMU8zSWZqeUV2REc2cmd2R1lhcWxrWG9ZSm81Z3RKLWRHVW9ZNy1tSWRIam1adHd5TXFzN2VqZ25GanZia0tOUk51QzhHN1EtMWNhb3dTWGkxaXFKTUNEZERhQ2dZS0FTQVNBUklTRlFIR1gyTWktOHNwS2JrRmdSOGQ3ZWdSbkFRaTl3MDIwN5SMBmV4cGlyeZSMCGRhdGV0aW1llIwIZGF0ZXRpbWWUk5RDCgfqARcHKTcNVuqUhZRSlIwOX3JlZnJlc2hfdG9rZW6UjGcxLy8wZVZmd2hzV2NoS2taQ2dZSUFSQUFHQTRTTndGLUw5SXJPX0FvcDBkSnJUMVo4LWV2ZDdmSEVKS2o0WFBfNmVrT1BMUGNoUjlhQzg0Tkt6S2QzQmdTZjNnZnJpREV5VU50bkZnlIwJX2lkX3Rva2VulE6MB19zY29wZXOUXZSMJWh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL2F1dGgvZHJpdmWUYYwPX2RlZmF1bHRfc2NvcGVzlE6MD19ncmFudGVkX3Njb3Blc5RdlIwlaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vYXV0aC9kcml2ZZRhjApfdG9rZW5fdXJplIwjaHR0cHM6Ly9vYXV0aDIuZ29vZ2xlYXBpcy5jb20vdG9rZW6UjApfY2xpZW50X2lklIxIMTMyODIzMDc5MzI2LWg5Y3ZqNWVhaGlnbThocDlxMGI3dDVyazc3Ymh1M2dwLmFwcHMuZ29vZ2xldXNlcmNvbnRlbnQuY29tlIwOX2NsaWVudF9zZWNyZXSUjCNHT0NTUFgtT0hyUXJHZDdKZGpTdkZHaFJIV3JDX1Exb3FMZpSMEV9xdW90YV9wcm9qZWN0X2lklE6MC19yYXB0X3Rva2VulE6MFl9lbmFibGVfcmVhdXRoX3JlZnJlc2iUiYwPX3RydXN0X2JvdW5kYXJ5lE6MEF91bml2ZXJzZV9kb21haW6UjA5nb29nbGVhcGlzLmNvbZSMD19jcmVkX2ZpbGVfcGF0aJROjBlfdXNlX25vbl9ibG9ja2luZ19yZWZyZXNolImMCF9hY2NvdW50lIwAlHViLg==
kind: Secret
metadata:
name: google-drive-credentials
namespace: momo
type: Opaque
stringData:
# 實際部署請透過 kubectl create secret 或外部 secret manager 注入。
google_credentials.json: "<GOOGLE_DRIVE_CREDENTIALS_JSON>"
google_token.pickle: "<GOOGLE_DRIVE_TOKEN_PICKLE_BASE64>"

View File

@@ -11,29 +11,29 @@ metadata:
type: Opaque
stringData:
# PostgreSQL
POSTGRES_USER: "momo"
POSTGRES_PASSWORD: "wooo_pg_2026"
DATABASE_URL: "postgresql://momo:wooo_pg_2026@momo-postgres:5432/momo_analytics"
POSTGRES_USER: "<POSTGRES_USER>"
POSTGRES_PASSWORD: "<POSTGRES_PASSWORD>"
DATABASE_URL: "postgresql://<POSTGRES_USER>:<POSTGRES_PASSWORD>@momo-postgres:5432/momo_analytics"
# App 認證
SECRET_KEY: "wooo-momo-secret-key-2026"
LOGIN_PASSWORD: "0936223270"
SECRET_KEY: "<SECRET_KEY>"
LOGIN_PASSWORD: "<LOGIN_PASSWORD>"
# Telegram Bot
TELEGRAM_BOT_TOKEN: "8075645931:AAH-EGKMo8ZC4QJs-Nc1_0s92xHrGdQvdpg"
TELEGRAM_CHAT_ID: "5619078117"
TELEGRAM_BOT_TOKEN: "<TELEGRAM_BOT_TOKEN>"
TELEGRAM_CHAT_ID: "<TELEGRAM_CHAT_ID>"
# LINE Notify
LINE_CHANNEL_ACCESS_TOKEN: "nD6MSXjB2FyB111zpT6Yik5B275mi6olHjjf94VnqN1ljUcqzcA7KtSSslxsOCEG6pERzmidNJFdzol6h+9V+t1x3j4Q8ljAacqC+i0627RuwbkiLxoHTJ/9HbIdehhoSJoeuNJHLraE721iDDfIuQdB04t89/1O/w1cDnyilFU="
LINE_CHANNEL_ACCESS_TOKEN: "<LINE_CHANNEL_ACCESS_TOKEN>"
# Email
EMAIL_HOST_PASSWORD: ""
# Gemini AI
GEMINI_API_KEY: "AIzaSyCqv7TY2iTGi2wa91d2irwH08VYXjT9YUk"
GEMINI_API_KEY: "<GEMINI_API_KEY>"
# Ollama AI (GCP 可能無法連到內網,視情況調整)
OLLAMA_API_KEY: "0df8b4f247a4497998248f013ce92a17.vqSWDEK0RppTZIwcdT-ei-Sz"
OLLAMA_API_KEY: "<OLLAMA_API_KEY>"
# App Password
APP_PASSWORD: "0936223270"
APP_PASSWORD: "<APP_PASSWORD>"

View File

@@ -43,14 +43,16 @@ data:
PASSWORD_REQUIRE_DIGIT: "false"
PASSWORD_REQUIRE_SPECIAL: "false"
# Ollama AI 服務 (GCP 可能無法連到內網 Ollama)
# 如需 AI 功能,請設定外網可存取的 Ollama 或改用 Gemini
OLLAMA_HOST: ""
OLLAMA_MODEL: "llama3:70b-instruct-q2_K"
# Ollama AI 服務ADR-027 三主機級聯GCP-A → GCP-B → 111
# GCP K8s 直接走 GCP Ollama 兩台公網 IPfailback 才走 111 內網。
OLLAMA_HOST_PRIMARY: "http://34.87.90.216:11434"
OLLAMA_HOST_SECONDARY: "http://34.21.145.224:11434"
OLLAMA_HOST_FALLBACK: "http://192.168.0.111:11434"
OLLAMA_MODEL: "qwen3:8b"
# Google Gemini AI 服務 (GCP 建議使用)
# Google Gemini AI 服務(成本節流 fallbackPhase 20 cost_throttle 啟用時)
GEMINI_MODEL: "gemini-1.5-flash"
AI_PROVIDER: "gemini"
AI_PROVIDER: "ollama"
# 外部服務連結GCP 版本)
METABASE_URL: ""

View File

@@ -75,8 +75,8 @@ alertmanager:
- name: 'null'
- name: 'telegram'
telegram_configs:
- bot_token: '8075645931:AAH-EGKMo8ZC4QJs-Nc1_0s92xHrGdQvdpg'
chat_id: 5619078117
- bot_token: '<TELEGRAM_BOT_TOKEN>'
chat_id: '<TELEGRAM_CHAT_ID>'
parse_mode: 'HTML'
message: |
{{ if eq .Status "firing" }}🚨🔥 <b>告警觸發</b> 🔥🚨{{ else }}✅💚 <b>告警恢復</b> 💚✅{{ end }}

View File

@@ -7,10 +7,10 @@ metadata:
namespace: tools
type: Opaque
stringData:
SUPERSET_SECRET_KEY: "wooo-superset-secret-key-2026-very-long-string"
ADMIN_PASSWORD: "Wooo_Superset_2026"
DATABASE_PASSWORD: "superset_db_2026"
REDIS_PASSWORD: ""
SUPERSET_SECRET_KEY: "<SUPERSET_SECRET_KEY>"
ADMIN_PASSWORD: "<SUPERSET_ADMIN_PASSWORD>"
DATABASE_PASSWORD: "<SUPERSET_DATABASE_PASSWORD>"
REDIS_PASSWORD: "<SUPERSET_REDIS_PASSWORD>"
---
# Superset Redis
@@ -220,7 +220,7 @@ spec:
name: superset-secret
key: ADMIN_PASSWORD
- name: DATABASE_URL
value: "postgresql+psycopg2://superset:superset_db_2026@superset-postgres:5432/superset"
value: "postgresql+psycopg2://superset:<SUPERSET_DATABASE_PASSWORD>@superset-postgres:5432/superset"
volumeMounts:
- name: superset-config
mountPath: /app/pythonpath/superset_config.py
@@ -242,7 +242,7 @@ spec:
name: superset-secret
key: SUPERSET_SECRET_KEY
- name: DATABASE_URL
value: "postgresql+psycopg2://superset:superset_db_2026@superset-postgres:5432/superset"
value: "postgresql+psycopg2://superset:<SUPERSET_DATABASE_PASSWORD>@superset-postgres:5432/superset"
- name: REDIS_HOST
value: "superset-redis"
volumeMounts:

View File

@@ -0,0 +1,155 @@
-- =============================================================================
-- Migration 024: ai_calls — 統一 LLM 呼叫遙測表
-- Operation Ollama-First v5.0 — Phase 1
-- 日期: 2026-05-03 台北
-- 對應戰役: docs/phase0_audit_report_20260503.md34 個 LLM 呼叫點AIGenerationHistory 覆蓋率 11.8%
-- =============================================================================
-- 說明:
-- 既有 ai_generation_history4 處)/ ai_usage_tracking通用皆未串接其餘
-- 30 個 LLM 呼叫點,無法支撐 Phase 5 Token 日報、Phase 9 預算告警、Phase 11 RAG。
-- ai_calls 為 append-only 遙測表,所有 LLM 調用統一寫入async fire-and-forget。
--
-- 設計決策(詳見 docs/phase1_db_design_20260503.md:
-- 1. BIGSERIAL90 天保留 ~6.5M 筆預留向上空間INT4 上限 21 億夠用,但與 mcp_calls 保持一致用 BIGSERIAL
-- 2. 不 partitionV16.5M / 90 天 ≈ 72k/dayPostgreSQL 單表可承受到 ~50M 才需要分區。
-- 若 Phase 5 後實測 query latency 退化或月寫入超 1M再切 monthly partition。
-- 3. 90 天 hot data以 created_at < NOW() - INTERVAL '90 days' DELETE由 scheduler 跑(不 archive
-- 4. cost_usd 預設 0由 logger 端依 provider+model 試算填入;不可信時保 0 不誤導
-- 5. JSONB meta 不加 GIN indexV1查詢需求未明避免寫入放大待 Phase 5 報表 patten 穩定再評估
--
-- 回滾腳本(緊急用):
-- DROP INDEX IF EXISTS idx_ai_calls_called_at;
-- DROP INDEX IF EXISTS idx_ai_calls_caller_called_at;
-- DROP INDEX IF EXISTS idx_ai_calls_provider_called_at;
-- DROP INDEX IF EXISTS idx_ai_calls_request_id;
-- DROP INDEX IF EXISTS idx_ai_calls_status_called_at;
-- DROP TABLE IF EXISTS ai_calls;
--
-- critic-A11 修補2026-05-03:
-- B2 → 026 加 pgcrypto extension
-- H1 → provider CHECK 白名單NOT VALID
-- H2 → meta/error 大小 CHECK
-- M3 → status NOT NULL + fallback_to consistency CHECK
-- M5 → partial index 精確列舉 ('error','timeout','fallback')
-- L3 → duration_ms 範圍 CHECK
-- =============================================================================
CREATE TABLE IF NOT EXISTS ai_calls (
id BIGSERIAL PRIMARY KEY,
called_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
-- 呼叫點識別A1 audit 34 點命名表logger 須限制在白名單;新增需 ADR
-- hermes_analyst, hermes_intent, hermes_ea_prefetch,
-- km_embedding_worker, km_embedding_realtime,
-- aider_heal,
-- mcp_l1_grounding, mcp_l2_grounding, mcp_l3_ollama,
-- openclaw_daily, openclaw_weekly, openclaw_monthly, openclaw_meta, openclaw_qa,
-- nemotron_dispatch,
-- code_review_hermes, code_review_openclaw, code_review_elephant,
-- ea_engine,
-- ppt_gemini, ppt_ollama, ppt_nim,
-- sales_copy, trend_match, trend_qa, product_insights, trend_keywords,
-- tg_bot_copy, tg_bot_copy_v2,
-- openclaw_bot_main, openclaw_bot_gemini, openclaw_bot_nim,
-- bot_api_copy, trend_crawler, ai_provider_generic
caller VARCHAR(64) NOT NULL,
-- 主機/供應商標籤A1 audit Section 1.1 主機標記原則)
-- gcp_ollama / ollama_111 / gemini / claude / nim / openrouter / nim_via_elephant
provider VARCHAR(32) NOT NULL,
model VARCHAR(128) NOT NULL,
input_tokens INTEGER NOT NULL DEFAULT 0,
output_tokens INTEGER NOT NULL DEFAULT 0,
duration_ms INTEGER,
-- ok / fallback / error / timeout / cache_only
-- fallback 表示「主路徑失敗,觸發了下游 caller」下游本身會另寫一筆 ok/error
-- M3: status NOT NULL且 fallback_to 必須與 status='fallback' 一致
status VARCHAR(16) NOT NULL,
fallback_to VARCHAR(64),
cost_usd NUMERIC(10,6) NOT NULL DEFAULT 0,
-- Anthropic / Gemini prompt cache 命中Phase 5 Token 日報降本指標)
cache_hit BOOLEAN NOT NULL DEFAULT FALSE,
-- Phase 11 RAG 預留:本次調用是否實質被 RAG 取代/前置攔截
rag_hit BOOLEAN NOT NULL DEFAULT FALSE,
-- 串接「同一邏輯請求」的多筆 call如 Code Review 三鏈、Q&A fallback 鏈)
request_id VARCHAR(64),
error TEXT,
-- prompt_hash / temperature / max_tokens / fingerprint / etc.(不存原始 prompt
meta JSONB,
-- ─────── critic-A11 修補:白名單 + PII/膨脹護欄 ───────
-- H1: provider 白名單NOT VALID 不檢既存資料,僅檢未來寫入)
-- 三主機架構(統帥 2026-05-03 確認):
-- gcp_ollama = Primary 34.87.90.216 (SSD)
-- ollama_secondary = Secondary 34.21.145.224 (SSD)
-- ollama_111 = Fallback 192.168.0.111 (HDD/Local)
CONSTRAINT chk_ai_calls_provider CHECK (
provider IN ('gcp_ollama','ollama_secondary','ollama_111','gemini','claude',
'nim','openrouter','nim_via_elephant')
),
-- M3: status 白名單 + fallback_to 一致性
CONSTRAINT chk_ai_calls_status CHECK (
status IN ('ok','fallback','error','timeout','cache_only')
),
CONSTRAINT chk_ai_calls_fallback_consistent CHECK (
(status = 'fallback') = (fallback_to IS NOT NULL)
),
-- L3: duration 範圍 (0 ~ 10 分鐘)
CONSTRAINT chk_ai_calls_duration_range CHECK (
duration_ms IS NULL OR (duration_ms >= 0 AND duration_ms <= 600000)
),
-- H2: meta/error 大小護欄(避免 PII 落地與膨脹)
CONSTRAINT chk_ai_calls_meta_size CHECK (
meta IS NULL OR octet_length(meta::text) <= 8192
),
CONSTRAINT chk_ai_calls_error_size CHECK (
error IS NULL OR octet_length(error) <= 4096
)
);
-- ─────────────────────────────────────────────────────────────────────────────
-- 索引設計
-- ─────────────────────────────────────────────────────────────────────────────
-- (1) 時間範圍掃描(日報/週報「過去 24h / 7d」必用BRIN 不適合 OLTP 隨機讀)
CREATE INDEX IF NOT EXISTS idx_ai_calls_called_at
ON ai_calls (called_at DESC);
-- (2) GROUP BY caller 報表(日報 Section 3 TOP caller / 全鏈 trace
CREATE INDEX IF NOT EXISTS idx_ai_calls_caller_called_at
ON ai_calls (caller, called_at DESC);
-- (3) 供應商分布報表(週報 by provider 統計、預算追蹤)
CREATE INDEX IF NOT EXISTS idx_ai_calls_provider_called_at
ON ai_calls (provider, called_at DESC);
-- (4) request_id 串鏈部分查詢sparse 欄位不全建)
CREATE INDEX IF NOT EXISTS idx_ai_calls_request_id
ON ai_calls (request_id)
WHERE request_id IS NOT NULL;
-- (5) 異常監控M5: 精確列舉 error/timeout/fallback避免未知 status 污染)
CREATE INDEX IF NOT EXISTS idx_ai_calls_status_called_at
ON ai_calls (status, called_at DESC)
WHERE status IN ('error','timeout','fallback');
-- ─────────────────────────────────────────────────────────────────────────────
-- 權限(沿襲 migration 023 慣例)
-- ─────────────────────────────────────────────────────────────────────────────
GRANT ALL PRIVILEGES ON ai_calls TO momo;
GRANT USAGE, SELECT ON SEQUENCE ai_calls_id_seq TO momo;
-- 註: 90 天保留由 scheduler 任務執行 (Phase 5 排程):
-- DELETE FROM ai_calls WHERE called_at < NOW() - INTERVAL '90 days';
-- 建議每日 03:00 跑,配合 idx_ai_calls_called_at DESC 倒序掃描可控制成本。
DO $$
BEGIN
RAISE NOTICE 'Migration 024 done: ai_calls + 5 indexes (Operation Ollama-First v5.0 P1)';
END $$;

View File

@@ -0,0 +1,204 @@
-- =============================================================================
-- Migration 025: mcp_calls + ai_call_budgets
-- Operation Ollama-First v5.0 — Phase 1 (Phase 10 MCP / Phase 9 預算告警 預備)
-- 日期: 2026-05-03 台北
-- =============================================================================
-- 說明:
-- mcp_calls — Phase 10 引入 5 個 MCP server 後的遙測表Schema 先到位。
-- 與 ai_calls 分表,因 MCP 沒有 token 概念、計費邏輯不同。
-- ai_call_budgets — Phase 9 預算告警表;種子資料即立即可用。
--
-- 設計決策:
-- 1. mcp_calls.insight_id 不加 FK避免 cascadePhase 11 ai_insights 會頻繁 archive
-- 改用「軟連結」+ 應用層 join保留可被 NULL 化的彈性。
-- 2. ai_call_budgets.provider NULL = 全供應商總額UNIQUE constraint 用 (period, provider)
-- 若 NULL 行為不一致需保護,由應用層強制單例)
-- 註: PostgreSQL 預設 NULL != NULL所以同 period 多筆 provider=NULL 會通過 UNIQUE
-- 需應用層自律或改用部分索引(見下方)。
--
-- 回滾腳本:
-- DROP INDEX IF EXISTS idx_mcp_calls_called_at;
-- DROP INDEX IF EXISTS idx_mcp_calls_caller_called_at;
-- DROP INDEX IF EXISTS idx_mcp_calls_server_tool;
-- DROP INDEX IF EXISTS idx_mcp_calls_status_called_at;
-- DROP INDEX IF EXISTS uq_ai_call_budgets_period_null_provider;
-- DROP TABLE IF EXISTS mcp_calls;
-- DROP TABLE IF EXISTS ai_call_budgets;
-- =============================================================================
-- ─────────────────────────────────────────────────────────────────────────────
-- mcp_calls — MCP Server 呼叫遙測Phase 10 預備)
-- ─────────────────────────────────────────────────────────────────────────────
CREATE TABLE IF NOT EXISTS mcp_calls (
id BIGSERIAL PRIMARY KEY,
called_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
-- 與 ai_calls.caller 同一張白名單,便於跨表 trace
caller VARCHAR(64) NOT NULL,
-- omnisearch / firecrawl / postgres / playwright / filesystem / git
server VARCHAR(64) NOT NULL,
-- search / scrape / query / read_file / git_log / ...
tool VARCHAR(128) NOT NULL,
input_args JSONB,
output_size INTEGER, -- bytes異常巨大可警示
duration_ms INTEGER,
-- M1: NOT NULL 對齊 ai_calls
status VARCHAR(16) NOT NULL,
error TEXT,
cost_usd NUMERIC(10,6) NOT NULL DEFAULT 0,
cache_hit BOOLEAN NOT NULL DEFAULT FALSE,
-- M6: 跨 ai_calls/mcp_calls 串鏈用Phase 10 後 LLM→MCP→LLM 鏈不可斷)
request_id VARCHAR(64),
-- 軟連結:若 MCP 結果被 embed 寫入 ai_insights記錄 insight_id 但不加 FK
insight_id BIGINT,
-- ─────── critic-A11 修補:白名單 + PII/膨脹護欄 ───────
-- M1: status 白名單
CONSTRAINT chk_mcp_calls_status CHECK (
status IN ('ok','error','timeout','rate_limited','cache_only')
),
-- L3: duration 範圍
CONSTRAINT chk_mcp_calls_duration_range CHECK (
duration_ms IS NULL OR (duration_ms >= 0 AND duration_ms <= 600000)
),
-- H2: input_args / error 大小護欄postgres-mcp 可能含 SQL含 PII 風險)
CONSTRAINT chk_mcp_calls_args_size CHECK (
input_args IS NULL OR octet_length(input_args::text) <= 16384
),
CONSTRAINT chk_mcp_calls_error_size CHECK (
error IS NULL OR octet_length(error) <= 4096
)
);
CREATE INDEX IF NOT EXISTS idx_mcp_calls_called_at
ON mcp_calls (called_at DESC);
CREATE INDEX IF NOT EXISTS idx_mcp_calls_caller_called_at
ON mcp_calls (caller, called_at DESC);
CREATE INDEX IF NOT EXISTS idx_mcp_calls_server_tool
ON mcp_calls (server, tool, called_at DESC);
-- M5: 異常監控 partial 精確列舉
CREATE INDEX IF NOT EXISTS idx_mcp_calls_status_called_at
ON mcp_calls (status, called_at DESC)
WHERE status IN ('error','timeout','rate_limited');
-- M6: request_id 串鏈部分索引sparse 不全建)
CREATE INDEX IF NOT EXISTS idx_mcp_calls_request_id
ON mcp_calls (request_id)
WHERE request_id IS NOT NULL;
GRANT ALL PRIVILEGES ON mcp_calls TO momo;
GRANT USAGE, SELECT ON SEQUENCE mcp_calls_id_seq TO momo;
-- ─────────────────────────────────────────────────────────────────────────────
-- ai_call_budgets — 預算與告警閾值Phase 9 預算守門)
-- ─────────────────────────────────────────────────────────────────────────────
CREATE TABLE IF NOT EXISTS ai_call_budgets (
id SERIAL PRIMARY KEY,
period VARCHAR(16) NOT NULL, -- daily / weekly / monthly
provider VARCHAR(32), -- NULL = 全供應商總額
budget_usd NUMERIC(10,2) NOT NULL,
alert_pct INTEGER NOT NULL DEFAULT 80, -- 達此百分比觸發 Telegram 告警
updated_at TIMESTAMPTZ DEFAULT NOW(),
CONSTRAINT chk_ai_budget_period
CHECK (period IN ('daily', 'weekly', 'monthly')),
CONSTRAINT chk_ai_budget_alert_pct
CHECK (alert_pct BETWEEN 1 AND 100),
CONSTRAINT chk_ai_budget_amount
CHECK (budget_usd > 0)
);
-- 部分唯一索引:分別處理 provider IS NULL 與 NOT NULL避免 NULL != NULL 漏洞
CREATE UNIQUE INDEX IF NOT EXISTS uq_ai_call_budgets_period_provider
ON ai_call_budgets (period, provider)
WHERE provider IS NOT NULL;
CREATE UNIQUE INDEX IF NOT EXISTS uq_ai_call_budgets_period_null_provider
ON ai_call_budgets (period)
WHERE provider IS NULL;
GRANT ALL PRIVILEGES ON ai_call_budgets TO momo;
GRANT USAGE, SELECT ON SEQUENCE ai_call_budgets_id_seq TO momo;
-- ─────────────────────────────────────────────────────────────────────────────
-- 種子資料(戰役 v5.0 規格 + critic-A11 H3 補 nim/nim_via_elephant/ollama
-- M2: ON CONFLICT 配 partial unique index 會炸;改用 WHERE NOT EXISTS 確保冪等
-- ─────────────────────────────────────────────────────────────────────────────
-- 全供應商總額period, provider=NULL
INSERT INTO ai_call_budgets (period, provider, budget_usd, alert_pct)
SELECT 'daily', NULL, 1.00, 80
WHERE NOT EXISTS (
SELECT 1 FROM ai_call_budgets WHERE period='daily' AND provider IS NULL
);
INSERT INTO ai_call_budgets (period, provider, budget_usd, alert_pct)
SELECT 'weekly', NULL, 5.00, 80
WHERE NOT EXISTS (
SELECT 1 FROM ai_call_budgets WHERE period='weekly' AND provider IS NULL
);
INSERT INTO ai_call_budgets (period, provider, budget_usd, alert_pct)
SELECT 'monthly', NULL, 20.00, 80
WHERE NOT EXISTS (
SELECT 1 FROM ai_call_budgets WHERE period='monthly' AND provider IS NULL
);
-- 個別供應商(含 H3 修補:補 nim / nim_via_elephant / ollama 雙線)
INSERT INTO ai_call_budgets (period, provider, budget_usd, alert_pct)
SELECT 'monthly', 'claude', 10.00, 80
WHERE NOT EXISTS (
SELECT 1 FROM ai_call_budgets WHERE period='monthly' AND provider='claude'
);
INSERT INTO ai_call_budgets (period, provider, budget_usd, alert_pct)
SELECT 'monthly', 'gemini', 8.00, 80
WHERE NOT EXISTS (
SELECT 1 FROM ai_call_budgets WHERE period='monthly' AND provider='gemini'
);
-- H3: NIM 兩條獨立計費鏈NemoTron 配額 + ElephantAlpha 49B各設預算
INSERT INTO ai_call_budgets (period, provider, budget_usd, alert_pct)
SELECT 'monthly', 'nim', 5.00, 80
WHERE NOT EXISTS (
SELECT 1 FROM ai_call_budgets WHERE period='monthly' AND provider='nim'
);
INSERT INTO ai_call_budgets (period, provider, budget_usd, alert_pct)
SELECT 'monthly', 'nim_via_elephant', 5.00, 80
WHERE NOT EXISTS (
SELECT 1 FROM ai_call_budgets WHERE period='monthly' AND provider='nim_via_elephant'
);
-- H3: OpenRouterPPT deepseek-v3.2
INSERT INTO ai_call_budgets (period, provider, budget_usd, alert_pct)
SELECT 'monthly', 'openrouter', 3.00, 80
WHERE NOT EXISTS (
SELECT 1 FROM ai_call_budgets WHERE period='monthly' AND provider='openrouter'
);
-- Ollama 雙線(免費,但設極低預算 + alert=100% 統一告警邏輯,異常激增可警示)
INSERT INTO ai_call_budgets (period, provider, budget_usd, alert_pct)
SELECT 'monthly', 'gcp_ollama', 0.01, 100
WHERE NOT EXISTS (
SELECT 1 FROM ai_call_budgets WHERE period='monthly' AND provider='gcp_ollama'
);
INSERT INTO ai_call_budgets (period, provider, budget_usd, alert_pct)
SELECT 'monthly', 'ollama_111', 0.01, 100
WHERE NOT EXISTS (
SELECT 1 FROM ai_call_budgets WHERE period='monthly' AND provider='ollama_111'
);
DO $$
BEGIN
RAISE NOTICE 'Migration 025 done: mcp_calls + ai_call_budgets + 10 seed budgets (Operation Ollama-First v5.0 P1, critic-A11 fixes B2/H1/H2/H3/M1/M2/M5/M6/L3 applied)';
END $$;

View File

@@ -0,0 +1,66 @@
-- =============================================================================
-- Migration 026: ai_insights.embedding_signature — BGE-M3 一致性護欄
-- Operation Ollama-First v5.0 — Phase 1 / 護欄 #3
-- 日期: 2026-05-03 台北
-- 對應: docs/phase0_audit_report_20260503.md Section 3 BGE-M3 一致性現況報告
-- =============================================================================
-- 風險背景:
-- bge-m3:latest 為 floating tagOllama upgrade 會悄悄跳版本,且程式未顯式
-- 傳遞 normalize / pooling 參數。RAG 召回率會無告警地退化。
--
-- 護欄設計:
-- 每筆 ai_insights.embedding 寫入時,同步記錄 signature
-- SHA1("{model}|{normalize}|{dim}|{ollama_digest_前12碼}") 取前 12 碼
-- 範例: bge-m3:latest|true|1024|7907646426 → SHA1 → e3b0c44298fc
--
-- Phase 11 啟動前,先批次補齊既有資料:
-- UPDATE ai_insights
-- SET embedding_signature = '<current_signature>'
-- WHERE embedding IS NOT NULL AND embedding_signature IS NULL;
-- 並由 ai_calls.meta.embedding_signature 與 ai_insights.embedding_signature
-- 做 cross-check簽名漂移時觸發 Telegram 告警)。
--
-- ALTER TABLE 安全性:
-- PostgreSQL 11+ 新增 NULL 預設值欄位為 metadata-only 變更(不重寫表,不鎖表)。
-- 生產環境 (PostgreSQL 14) 確認安全。
--
-- 回滾腳本:
-- DROP INDEX IF EXISTS idx_ai_insights_embedding_signature;
-- ALTER TABLE ai_insights DROP COLUMN IF EXISTS embedding_signature;
--
-- critic-A11 修補B2:
-- pgcrypto extension 由本 migration 啟用;附錄 SHA1 範例不再缺前置條件。
-- =============================================================================
-- (0) critic-A11 B2 修補pgcrypto 用於附錄 SHA1 簽名計算IF NOT EXISTS 冪等)
CREATE EXTENSION IF NOT EXISTS pgcrypto;
-- (1) 新增欄位(無 DEFAULTmetadata-only不鎖表
ALTER TABLE ai_insights
ADD COLUMN IF NOT EXISTS embedding_signature VARCHAR(64);
COMMENT ON COLUMN ai_insights.embedding_signature IS
'BGE-M3 一致性簽名SHA1({model}|{normalize}|{dim}|{ollama_digest})[:12]'
'Phase 11 RAG 召回前必檢查NULL = 既有未回填資料(待批次補)';
-- (2) Partial index只索引有 embedding 且簽名非空的列
-- 用 CONCURRENTLY 避免阻塞既有 ai_insights 寫入
-- 注意: CONCURRENTLY 不能在 transaction block 內執行;本 migration 採 PostgreSQL
-- psql 直接執行(無外層 BEGIN/COMMIT
CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_ai_insights_embedding_signature
ON ai_insights (embedding_signature)
WHERE embedding IS NOT NULL;
-- 註: Phase 11 啟動前批次補簽名範例(不在本 migration 執行):
-- WITH sig AS (
-- SELECT 'bge-m3:latest|true|1024|<digest>' AS raw
-- )
-- UPDATE ai_insights
-- SET embedding_signature = SUBSTRING(ENCODE(DIGEST(sig.raw, 'sha1'), 'hex'), 1, 12)
-- FROM sig
-- WHERE embedding IS NOT NULL AND embedding_signature IS NULL;
DO $$
BEGIN
RAISE NOTICE 'Migration 026 done: ai_insights.embedding_signature + partial index (Operation Ollama-First v5.0 P1)';
END $$;

View File

@@ -0,0 +1,126 @@
-- =============================================================================
-- Migration 027: rag_query_log — RAG 查詢遙測 (audit log)
-- Operation Ollama-First v5.0 — Phase 11
-- 日期: 2026-05-03 台北
-- 對應戰役: ADR-029Hermes-First 雙塔)+ Phase 11 RAG 自主學習迴圈
-- =============================================================================
-- 說明:
-- 每次 RAG 召回hermes_qa / openclaw_qa / etc.寫一筆append-only。
-- 核心指標:
-- - hit_count : top_k 召回實際命中數threshold 過濾後)
-- - saved_call : 命中且最終未升級到 LLM => 真實節省成本
-- - feedback_score : Telegram 👍/👎 後填回NULL = 尚未反饋)
-- 與 ai_calls / mcp_calls 透過 request_id 串鏈,跨表 trace 同一邏輯請求。
--
-- 設計決策:
-- 1. embedding 與 ai_insights 同維度 1024 (bge-m3),可跨表計 cosine
-- 2. ivfflat lists=100 對齊既有風格;資料量達 1M 後依 sqrt(N) 重建
-- 009 ai_insights 用 HNSW但本表寫入頻繁 + 不需即時最近鄰 query
-- 採 ivfflat 寫入便宜weekly 排程 REINDEX 即可,詳見 design doc
-- 3. used_results BIGINT[] 紀錄命中的 ai_insights.id方便事後召回率分析
-- (不加 FKai_insights 可能 archive避免 cascade
-- 4. query_text 限 4KBquery_text 可能含 PII用戶問題
-- 90 天保留 + 後續 PromotionGate 過濾後才允許進 ai_insights
-- 5. caller 與 ai_calls.caller 共白名單(不重複定義 CHECK避免雙寫漂移
-- 由 application logger 端強制DB 端僅檢長度)
--
-- 回滾腳本(緊急用):
-- DROP INDEX IF EXISTS idx_rag_query_log_embedding;
-- DROP INDEX IF EXISTS idx_rag_query_log_request_id;
-- DROP INDEX IF EXISTS idx_rag_query_log_caller;
-- DROP INDEX IF EXISTS idx_rag_query_log_queried_at;
-- DROP TABLE IF EXISTS rag_query_log;
-- =============================================================================
CREATE TABLE IF NOT EXISTS rag_query_log (
id BIGSERIAL PRIMARY KEY,
queried_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
-- 與 ai_calls.caller 同一張白名單hermes_qa / openclaw_qa / ...
caller VARCHAR(64) NOT NULL,
-- 用戶查詢PII 風險,限 4KB不 normalize 以保留原始查詢樣貌)
query_text TEXT NOT NULL,
-- bge-m3 embedding1024 維,與 ai_insights.embedding 同源;可 NULL = embedding 失敗仍記錄此次嘗試)
query_embedding VECTOR(1024),
-- 召回參數
top_k INTEGER NOT NULL DEFAULT 5,
threshold NUMERIC(4,3) NOT NULL DEFAULT 0.85,
-- 召回結果
hit_count INTEGER NOT NULL DEFAULT 0,
used_results BIGINT[], -- 命中的 ai_insights.id 陣列(軟連結,不加 FK
-- 是否成功避免 LLM 呼叫(核心成本指標)
saved_call BOOLEAN NOT NULL DEFAULT FALSE,
-- Telegram 👍/👎 反饋1-5NULL = 未反饋)
feedback_score INTEGER,
-- 與 ai_calls.request_id 串鏈
request_id VARCHAR(64),
-- ─────── 護欄 (對齊 critic-A11 風格) ───────
CONSTRAINT chk_rag_threshold CHECK (
threshold BETWEEN 0 AND 1
),
CONSTRAINT chk_rag_top_k CHECK (
top_k BETWEEN 1 AND 50
),
CONSTRAINT chk_rag_hit_count CHECK (
hit_count >= 0 AND hit_count <= top_k
),
CONSTRAINT chk_rag_query_size CHECK (
octet_length(query_text) <= 4096
),
CONSTRAINT chk_rag_feedback CHECK (
feedback_score IS NULL OR feedback_score BETWEEN 1 AND 5
),
-- saved_call=TRUE 必須有命中hit_count > 0才合理
CONSTRAINT chk_rag_saved_consistent CHECK (
(saved_call = FALSE) OR (hit_count > 0)
)
);
-- ─────────────────────────────────────────────────────────────────────────────
-- 索引設計
-- ─────────────────────────────────────────────────────────────────────────────
-- (1) 時間範圍掃描(日報 / 命中率報表)
CREATE INDEX IF NOT EXISTS idx_rag_query_log_queried_at
ON rag_query_log (queried_at DESC);
-- (2) caller 分布(哪個入口 RAG 命中率高)
CREATE INDEX IF NOT EXISTS idx_rag_query_log_caller
ON rag_query_log (caller, queried_at DESC);
-- (3) request_id 串鏈部分索引sparse 不全建)
CREATE INDEX IF NOT EXISTS idx_rag_query_log_request_id
ON rag_query_log (request_id)
WHERE request_id IS NOT NULL;
-- (4) pgvector ivfflatcosine similarity只索引非 NULL embedding
-- 注意: ivfflat 須先有資料才能正確訓練 lists空表建索引會 fallback exact scan
-- Phase 11 灌入首批查詢後若效能退化REINDEX CONCURRENTLY 重訓
CREATE INDEX IF NOT EXISTS idx_rag_query_log_embedding
ON rag_query_log
USING ivfflat (query_embedding vector_cosine_ops)
WITH (lists = 100)
WHERE query_embedding IS NOT NULL;
-- ─────────────────────────────────────────────────────────────────────────────
-- 權限
-- ─────────────────────────────────────────────────────────────────────────────
GRANT ALL PRIVILEGES ON rag_query_log TO momo;
GRANT USAGE, SELECT ON SEQUENCE rag_query_log_id_seq TO momo;
-- 註: 90 天保留由 scheduler 任務執行(與 ai_calls 對齊):
-- DELETE FROM rag_query_log WHERE queried_at < NOW() - INTERVAL '90 days';
-- 建議 03:30 跑ai_calls 03:00 之後),避免 IO 尖峰
DO $$
BEGIN
RAISE NOTICE 'Migration 027 done: rag_query_log + 4 indexes (ivfflat 1024d) (Operation Ollama-First v5.0 P11)';
END $$;

View File

@@ -0,0 +1,169 @@
-- =============================================================================
-- Migration 028: learning_episodes — 蒸餾池 / 知識庫前哨
-- Operation Ollama-First v5.0 — Phase 11
-- 日期: 2026-05-03 台北
-- 對應戰役: ADR-029Hermes-First+ Phase 11 PromotionGate 4 階段過濾
-- =============================================================================
-- 說明:
-- LLM/MCP 結果先寫入 learning_episodes蒸餾池過 4 階段 PromotionGate
-- 才晉升 ai_insights知識庫主檔。設計目的
-- - 隔離未驗證內容,避免直接污染 RAG 召回語料
-- - 保留 raw + distilled方便事後重訓
-- - 高權重(>=0.8)走人工驗收,低權重走自動晉升
--
-- PromotionGate 狀態機:
-- pending
-- ├─[Stage 1: quality<0.7]→ rejected_quality
-- ├─[Stage 2: 規則檢測幻覺]→ rejected_hallucination
-- ├─[Stage 3: 與既有 insight cosine>0.95]→ rejected_duplicate
-- ├─[Stage 4a: weight<0.8 + 過 1-3]→ approved → 寫 ai_insights → insight_id 回填
-- └─[Stage 4b: weight>=0.8]→ awaiting_review → Telegram 推播
-- ├─[人工 👍]→ approved
-- ├─[人工 👎]→ rejected_human
-- └─[24h 無反饋]→ expired (weight 降為 0.5 重走 Stage 4a)
--
-- 設計決策:
-- 1. insight_id 軟連結(不加 FK—— ai_insights archive 不應 cascade 影響蒸餾池
-- 2. source_table + source_id 軟連結到 ai_calls / mcp_calls方便事後重訓溯源
-- 3. embedding 與 rag_query_log 同 1024 維,跨表 cosine 一致
-- 4. 不設 90 天保留蒸餾池長期保留approved/rejected_* 進冷儲檔由後續 ADR 定)
-- —— 短期內暴增風險:靠 partial index + monthly archive scheduler 控制
-- 5. promotion_status 用 VARCHAR(32) + CHECK 白名單;不上 ENUM 因新增狀態方便
-- 6. rejected_reason CHECK 強制 rejected_* 狀態必填,避免「沒原因的拒絕」
-- 7. human_approver 存 Telegram username 的 SHA1[:8],避免 PII 落地
--
-- 回滾腳本(緊急用):
-- DROP INDEX IF EXISTS idx_le_embedding;
-- DROP INDEX IF EXISTS idx_le_insight_id;
-- DROP INDEX IF EXISTS idx_le_episode_type;
-- DROP INDEX IF EXISTS idx_le_status;
-- DROP INDEX IF EXISTS idx_le_created_at;
-- DROP TABLE IF EXISTS learning_episodes;
-- =============================================================================
CREATE TABLE IF NOT EXISTS learning_episodes (
id BIGSERIAL PRIMARY KEY,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
-- 來源類型
-- mcp_result = MCP server 抓回的事實grounding / search / db query
-- llm_response = LLM 生成的洞察 / 摘要hermes_analyst / openclaw 等)
-- user_feedback = 用戶 Telegram 直接告知的事實(高 weight需人工確認
-- manual_curated = 人工手動入庫(最高 weight跳 PromotionGate
episode_type VARCHAR(32) NOT NULL,
-- 軟連結來源(不加 FK
source_table VARCHAR(32), -- 'ai_calls' / 'mcp_calls' / NULL
source_id BIGINT, -- 對應 source_table 的 id
-- 蒸餾後的精煉文本≤16KBraw 不存在此表,由 source_table 透過 source_id 回查)
distilled_text TEXT NOT NULL,
embedding VECTOR(1024), -- 與 ai_insights / rag_query_log 同維
-- 蒸餾品質評分0-1
-- <0.7 → Stage 1 直接 rejected_quality
-- >=0.7 → 進 Stage 2-3
quality_score NUMERIC(4,3) NOT NULL DEFAULT 0.0,
-- 權重(影響晉升路徑)
-- <0.8 → Stage 4a 自動晉升
-- >=0.8 → Stage 4b 人工驗收
weight NUMERIC(4,3) NOT NULL DEFAULT 0.5,
-- PromotionGate 狀態(見上方狀態機)
promotion_status VARCHAR(32) NOT NULL DEFAULT 'pending',
-- 晉升結果
insight_id BIGINT, -- 晉升後對應 ai_insights.id軟連結無 FK
rejected_reason TEXT, -- promotion_status=rejected_* 時必填
human_approver VARCHAR(64), -- Telegram username SHA1[:8]
reviewed_at TIMESTAMPTZ,
-- ─────── 護欄 (對齊 critic-A11 風格) ───────
CONSTRAINT chk_le_quality CHECK (
quality_score BETWEEN 0 AND 1
),
CONSTRAINT chk_le_weight CHECK (
weight BETWEEN 0 AND 1
),
CONSTRAINT chk_le_episode_type CHECK (
episode_type IN ('mcp_result','llm_response','user_feedback','manual_curated')
),
CONSTRAINT chk_le_status CHECK (
promotion_status IN (
'pending','approved','awaiting_review',
'rejected_quality','rejected_hallucination','rejected_duplicate','rejected_human',
'expired'
)
),
CONSTRAINT chk_le_distilled_size CHECK (
octet_length(distilled_text) <= 16384
),
CONSTRAINT chk_le_rejected_reason CHECK (
(promotion_status NOT LIKE 'rejected_%') OR (rejected_reason IS NOT NULL)
),
-- approved 必須有 insight_id其他狀態不應有
CONSTRAINT chk_le_approved_consistent CHECK (
(promotion_status = 'approved') = (insight_id IS NOT NULL)
),
-- source_table + source_id 一致性(要嘛兩個都 NULL要嘛兩個都有
CONSTRAINT chk_le_source_consistent CHECK (
(source_table IS NULL AND source_id IS NULL)
OR (source_table IS NOT NULL AND source_id IS NOT NULL)
),
CONSTRAINT chk_le_source_table CHECK (
source_table IS NULL OR source_table IN ('ai_calls','mcp_calls')
),
-- 人工驗收時 reviewed_at 必填
CONSTRAINT chk_le_review_consistent CHECK (
(human_approver IS NULL) OR (reviewed_at IS NOT NULL)
)
);
-- ─────────────────────────────────────────────────────────────────────────────
-- 索引設計
-- ─────────────────────────────────────────────────────────────────────────────
-- (1) 時間範圍掃描(蒸餾池規模監控)
CREATE INDEX IF NOT EXISTS idx_le_created_at
ON learning_episodes (created_at DESC);
-- (2) 待處理佇列查詢PromotionGate worker / 人工驗收 dashboard
-- partial index 縮體積:只關心 pending / awaiting_review 兩種「活躍」狀態
CREATE INDEX IF NOT EXISTS idx_le_status
ON learning_episodes (promotion_status, created_at DESC)
WHERE promotion_status IN ('pending','awaiting_review');
-- (3) 來源類型分布報表
CREATE INDEX IF NOT EXISTS idx_le_episode_type
ON learning_episodes (episode_type, created_at DESC);
-- (4) insight_id 反查(從 ai_insights 反推蒸餾來源)
CREATE INDEX IF NOT EXISTS idx_le_insight_id
ON learning_episodes (insight_id)
WHERE insight_id IS NOT NULL;
-- (5) pgvector ivfflatStage 3 重複檢測 cosine query 主用)
CREATE INDEX IF NOT EXISTS idx_le_embedding
ON learning_episodes
USING ivfflat (embedding vector_cosine_ops)
WITH (lists = 100)
WHERE embedding IS NOT NULL;
-- ─────────────────────────────────────────────────────────────────────────────
-- 權限
-- ─────────────────────────────────────────────────────────────────────────────
GRANT ALL PRIVILEGES ON learning_episodes TO momo;
GRANT USAGE, SELECT ON SEQUENCE learning_episodes_id_seq TO momo;
-- 註: expired 狀態降權 worker24h 無反饋)由 scheduler 跑:
-- UPDATE learning_episodes
-- SET promotion_status='expired', weight=0.5
-- WHERE promotion_status='awaiting_review'
-- AND created_at < NOW() - INTERVAL '24 hours';
-- 之後由 PromotionGate Stage 4a 重跑該批 expired 走自動晉升路徑。
DO $$
BEGIN
RAISE NOTICE 'Migration 028 done: learning_episodes + 5 indexes + 9 CHECK constraints (Operation Ollama-First v5.0 P11)';
END $$;

Some files were not shown because too many files have changed in this diff Show More