Commit Graph

338 Commits

Author SHA1 Message Date
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
OoO
7b6423fa67 fix(openclaw): route wakeup phrases back to menu
All checks were successful
CD Pipeline / deploy (push) Successful in 2m55s
2026-05-02 16:03:49 +08:00
OoO
673982d83b Fix OpenClaw callback command path from NL dispatch regression
All checks were successful
CD Pipeline / deploy (push) Successful in 4m17s
2026-05-02 15:59:54 +08:00
OoO
76304602b1 fix(ppt): footer→bottom, font spec (Courier New/Microsoft JhengHei), 50-item paginated table, remove old single-page remnant
All checks were successful
CD Pipeline / deploy (push) Successful in 2m41s
2026-05-02 15:32:54 +08:00
OoO
0b82350745 style(ppt): comprehensive warm-tone redesign - caramel KPI cards, warm paper MCP/AI pages, revenue ratio bars in product table, chart→caramel orange, cover with warm decorative bands 2026-05-02 15:20:02 +08:00
OoO
ccc0cef9be feat(ppt): upgrade monthly AI prompt to 7-section expert template with MCP RAG integration, enrich data_summary with category/product breakdown
All checks were successful
CD Pipeline / deploy (push) Successful in 2m47s
2026-05-02 15:06:16 +08:00
OoO
4c6e4ca5fb style(ppt): align PPT palette perfectly with MOMO Pro v2 design tokens (Beige, Warm Ink, Caramel Orange) as per frontend upgrade roadmap 2026-05-02 15:01:55 +08:00
OoO
934adc957c style(ppt): redesign ppt layouts, align palette with frontend, and add dedicated MCP RAG slide 2026-05-02 14:59:45 +08:00
OoO
9068d463bb feat(ea): execute Phase 3 C-series architecture fixes to prevent recurrence
All checks were successful
CD Pipeline / deploy (push) Successful in 2m37s
- C1: Removed weekly_strategy and meta_analysis from Elephant Alpha's SAFE_ACTIONS (orchestrator prompt and engine _ACTION_ZH) to prevent autonomous generation of scheduled reports
- C2: Removed hardcoded 0.85 confidence example from orchestrator prompt and implemented bounding validation (0.0~1.0) in _parse_strategic_decision
- C3: Expanded ADR-019 data freshness gate (_ppt_check_data_freshness) to cover /ppt weekly and /ppt strategy routes, proactively warning users of stale data
2026-05-02 14:39:10 +08:00
OoO
9158bbe1a6 fix(ea): execute Phase 2 B-series data quality and gate improvements
All checks were successful
CD Pipeline / deploy (push) Successful in 2m40s
- B1 & B2: Updated SQL column names from 銷售金額 to 總業績 in openclaw_strategist_service.py and chart_generator_service.py
- B3: Removed bare except statements in DB fetchers to raise errors instead of failing silently
- B4: Implemented freshness gate (MAX(snapshot_date) < CURRENT_DATE - 2) in daily_sales_snapshot to prevent generating stale reports and send data stalled alerts
- B5: Replaced hardcoded 45.0 system load percentage with actual psutil CPU metric
2026-05-02 14:34:30 +08:00
OoO
e6df2fad28 fix(ea): remove weekly_strategy/meta_analysis from autonomous engine triggers (Phase 1 stopgap)
All checks were successful
CD Pipeline / deploy (push) Successful in 2m39s
Critic-approved 3-point revision (REVISE → adopted):
1. Disable weekly_insight trigger at definition (line 279-285) — EA no
   longer evaluates the 6h / >=5 ai_insights condition that fired
   _generate_strategy_report without force_tg_alert=True.
2. Remove the openclaw weekly/meta dispatch table branches (line 591-606).
   The 5 actions (generate_strategic_analysis, generate_weekly_strategy,
   generate_market_analysis, generate_pricing_strategy,
   generate_meta_analysis) now fall through to the existing
   `raise ValueError(f"Unrecognized step: ...")` at line 631, which
   _execute_decision's try/except converts into a circuit-breaker failure.
   This is the correct failure semantics critic asked for.
3. Convert _generate_strategy_report / _generate_meta_report into hard
   RuntimeError raisers and drop their imports of
   openclaw_strategist_service. Deep insurance: any future caller crashes
   immediately instead of silently bypassing dedupe.

Evidence: ai_insights logged 35+ duplicate weekly_strategy sends in 7 days
because EA's `_generate_strategy_report` invoked
generate_weekly_strategy_report() without force_tg_alert=True, bypassing
the run_scheduler.py weekly dedupe gate.

Out of scope (per task contract):
- run_scheduler.py:115 Monday 06:00 schedule — preserved (sole owner)
- services/openclaw_strategist_service.py — owned by B-series (SQL)
- Other EA triggers (price_drop_alert / market_opportunity /
  threat_escalation / code_exception / resource_optimization) — preserved
- Other dispatch branches (hermes / nemotron / auto_heal / code_fix /
  price_adjustment review) — preserved
- Did NOT add force_tg_alert=True defensive layer (critic flagged as
  anti-pattern)
- Did NOT touch _TRIGGER_TO_DECISION_TYPE / _ALLOWED_ACTION_TYPES

Not pushed, not deployed. D1 deployment will be issued separately and
must use `docker compose up -d --no-deps --force-recreate momo-scheduler`
(per feedback_compose_restart_vs_up).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-02 13:12:14 +08:00
OoO
477aab3f6f refactor(telegram): migrate edm_notifier text path to EventRouter (ADR-019 Phase 5)
Some checks failed
CD Pipeline / deploy (push) Has been cancelled
services/edm_notifier.py 的 _send_telegram() 處理 EDM 媒體告警,原本 if/else
分流 sendPhoto / sendMessage。

行為變化:
- 純文字分支(無 image_path):改走 services.event_router.dispatch_sync()
  event_type=edm_media_alert, severity=warning
- 含圖片分支(sendPhoto with multipart file upload):依 ADR-019 任務指示
  保留直連 Telegram API(EventRouter 不支援 file upload,列為 known skip)
- caller 行為不變,失敗仍 logger.error 不阻斷主線

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-02 13:09:34 +08:00
OoO
3e9d53c98c refactor(telegram): migrate aider_heal_executor sender to EventRouter (ADR-019 Phase 5)
services/aider_heal_executor.py 的 _notify_telegram() 為 ADR-013 AutoHeal 閉環
通知出口(aider 自動修復進度)。原直接 POST sendMessage,timeout=5s(非阻塞)。
改走 services.event_router.dispatch_sync()。

行為變化:
- 失敗仍靜默 pass,caller(execute_code_fix 等)行為完全不變
- severity=warning 會被 EventRouter classify 為 L0 或 L1(無 trace 時 L0),
  輕量分流不會拖慢自動修復流程
- 享 EventRouter 內建 retry + JSONL queue replay;舊版 timeout=5 失敗即丟訊息
  的問題改善(可從 queue 重送)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-02 13:09:34 +08:00
OoO
84786be06f refactor(telegram): migrate cicd_routes sender to EventRouter (ADR-019 Phase 5)
routes/cicd_routes.py 的 send_telegram_message() 用於 CI/CD pipeline 失敗 / Drone
build 異常等告警。原本直接 POST sendMessage,改走 services.event_router.
dispatch_sync()(event_type=cicd_pipeline_alert, severity=alert)。

行為變化:
- parse_mode 從 Markdown 改 HTML(EventRouter 統一);既有訊息中的 *bold* 等
  Markdown 控制字元會以純文字顯示,可讀性不受顯著影響
- 失敗保留 print + return False 同舊行為,不阻斷 caller(send_pipeline_failure_alert
  等)的 try/except 結構

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-02 13:09:34 +08:00
OoO
ea78d0814b refactor(telegram): migrate alert_routes sender to EventRouter (ADR-019 Phase 5)
routes/alert_routes.py 的 send_telegram_message() 是 Alertmanager webhook 通用告警
出口,原本直接 POST sendMessage 並對每個 chat_id 迴圈。改走 services.event_router.
dispatch_sync() 統一入口(event_type=alertmanager_webhook, severity=alert)。

行為變化:
- 移除手動 chat_id 迴圈,改傳 admin_chat_ids 給 EventRouter(內部仍逐一發)
- 新增 ADR-012 三層分流(L0/L1/L2)+ JSONL queue replay 失敗重送
- parse_mode 參數保留簽名向後相容,但實際統一走 EventRouter HTML 模板
- caller(Alertmanager webhook handler)的 try/except 結構未動

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-02 13:09:34 +08:00
OoO
edfe38e87d refactor(telegram): migrate nemoton_dispatcher sender to EventRouter (ADR-019 Phase 5)
NemoTron Dispatcher 的 _send_telegram() 原本直接 POST Telegram Bot API(含 MarkdownV2
跳脫)+ 透過 self.nm 走 NotificationManager 兩條路。改為統一走 services.event_router.
dispatch_sync(),享 EventRouter 的 retry + 失敗 JSONL queue replay + AI 三層分流。

行為變化:
- 從 _exec_trigger_price_alert / _exec_add_to_recommendation / _exec_flag_for_human_review
  三個工具實作流入 EventRouter,event_type=nemoton_dispatch_alert,severity=alert
- 移除 self.nm._send_telegram_messages() 的 short-circuit;改由 EventRouter 內建
  通道處理 chat_ids/token 解析
- 失敗時保留 logger.error + log fallback,不阻斷主線(同舊行為)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-02 13:09:34 +08:00
OoO
e12e6a8f96 feat(telegram): ADR-019 Phase 6 - daily data freshness probe + cron 09:05
Some checks failed
CD Pipeline / deploy (push) Has been cancelled
ADR-019 Phase 6:每日 09:05 OpenClawBot scheduler 主動巡檢 realtime_sales_monthly
最新資料日期,落後超過閾值時透過 EventRouter 發 Telegram 警告。

新增 services/data_freshness_probe.py:
- gap == 0:靜默不發(資料齊全)
- gap == 1:info(昨日資料齊,正常)
- gap == 2~3:warning
- gap >= 4:alert(P2,ETL 大概率出問題)
- latest_date 取不到:alert(DB 連線異常)

routes/openclaw_bot_routes.py 加 cron job openclaw_data_freshness_probe
(hour=9 minute=5,避開 09:00 的其他既有 job)。

從『用戶月初按按鈕踩坑才發現資料缺口』的被動模式,轉成 agent 主動巡檢通知。
配合 Phase 1(PPT freshness gate)+ Phase 2(agent tool)+ Phase 3(cmd 路徑
agent dispatch)+ Phase 4(對話 state),Telegram Bot 互動層的『rigid default
+ 靜默空白』反模式根除。

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-02 13:07:30 +08:00
OoO
14195b65fd feat(telegram): ADR-019 Phase 4 - conversation memory + chat_id propagation
All checks were successful
CD Pipeline / deploy (push) Successful in 2m51s
ADR-019 Phase 4:新增 services/openclaw_session.py 管理 chat_id 級別的多輪
對話歷史與 carry-over slot。In-memory,30 分鐘 TTL,重啟清空(臨時對話 state
不該污染 ai_insights 永久記憶)。

openclaw_answer 簽章加 chat_id=None 可選參數:
- 傳入時 agent 會看到該 chat 最近 5 輪對話歷史,注入 system prompt
- Ollama / Gemini FC 兩條路徑都會在生成成功後 append_turn 寫回 session
- system prompt 加決策規則:「若歷史顯示用戶剛被問參數,優先用該答案接續執行」

Caller 全部更新傳 chat_id:
- routes/openclaw_bot_routes.py:5479 (handle_cmd 不認識指令 fallback)
- routes/openclaw_bot_routes.py:5916 (webhook NL 路徑)
- routes/openclaw_bot_routes.py:_agent_dispatch_cmd (Phase 3 hook)
- services/telegram_bot_service.py:934 (polling NL fallback)

向下相容:chat_id=None 時行為與舊版完全相同(無 multi-turn 記憶)。

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-02 13:04:18 +08:00
OoO
38f4033eb0 feat(telegram): ADR-019 Phase 3 - feature-flagged agent dispatch for cmd:X
All checks were successful
CD Pipeline / deploy (push) Successful in 2m47s
ADR-019 Phase 3:在 handle_cmd 入口插入 agent dispatch hook,將白名單 cmd 翻成
NL question 交 OpenClaw agent 處理。Agent 自動透過 Phase 2 的 check_data_freshness
tool probe 資料缺口,缺資料時主動詢問用戶,避免靜默產出空白結果。

新增:
- 環境變數 OPENCLAW_AGENT_DISPATCH (預設 0)、OPENCLAW_AGENT_DISPATCH_CMDS (逗號分隔)
- _CMD_TO_NL 翻譯字典:sales / top / vendor 三 cmd 起步
- _agent_dispatch_cmd() helper:feature flag + 白名單 + agent 呼叫 + 失敗 fallback

設計考量:
- 預設 OFF,零 prod regression 風險
- Agent 失敗自動回原 handler,不卡用戶
- 灰度路徑:先在 staging 開 OPENCLAW_AGENT_DISPATCH=1 + CMDS=sales 觀察一週
- 21 cmd 不需要全部翻譯,只翻譯有「資料缺口可能性」或「參數需確認」的

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-02 13:00:02 +08:00
OoO
b3348ae77d feat(telegram): ADR-019 Phase 2 - check_data_freshness tool for OpenClaw
Some checks failed
CD Pipeline / deploy (push) Has been cancelled
ADR-019 Phase 2:把資料新鮮度查詢註冊為 OpenClaw 的第 4 個 Function Calling
tool。Agent 在回答任何特定時段業績問題前可主動 probe,避免月初/季初時編造
「業績為零」這類因 ETL 尚未匯入造成的虛假結論。

新增:
- _FC_TOOLS 加入 check_data_freshness 宣告
- _execute_tool 對應分支:回傳 latest_data_date / available_months /
  current_month_has_data / data_freshness_warning
- 系統 prompt 更新:明示 4 個工具與「相對時間詞先 probe」決策規則

與 Phase 1 互補:Phase 1 是 PPT cmd 路徑寫死的補丁,Phase 2 讓 NL 對話路徑
透過 agent 自己決策,是 ADR-019「Agent-First」原則的真正起點。

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-02 12:58:06 +08:00
OoO
db02ecf2cf feat(telegram): ADR-019 Phase 1 - PPT data freshness gate + store_insight fix
All checks were successful
CD Pipeline / deploy (push) Successful in 2m55s
ADR-019 Phase 1 (止血):PPT 生成前 probe 資料新鮮度。月初/缺資料期間用戶按
ppt:monthly/daily 不再產出空白報告,改主動 inline keyboard 詢問:
  - 改看最新有資料的月份/日期(一鍵)
  - 自訂月份/日期(接 await:date_ppt_*)
  - 取消

新增 PPTDataInsufficientError exception + _ppt_check_data_freshness() helper。
_generate_ppt_cmd 簽章加 _reply_to=None;_ppt_background 靜默吞此例外。

順手修同檔 :1976/:1993 兩處 store_insight() positional args 錯位 bug —
原本 (date, report_type, ai_text) 對應 signature (insight_type, content, period)
完全錯位,導致 period varchar(50) 被 2000 字 AI 內容截斷、INSERT 失敗、
ai_insights 表寫入永久失敗。改成 kwargs 呼叫。

ADR-019 (Telegram Bot Agentic Conversation Layer) 同步落地,Status: Accepted。
六 Phase 路線圖見 ADR 文件,本 commit 完成 Phase 1。

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-02 12:52:45 +08:00
OoO
1a886d962b fix(telegram): dedupe webhook+polling updates via shared DB guard
All checks were successful
CD Pipeline / deploy (push) Successful in 8m50s
Webhook (Flask) and polling (momo-telegram-bot) consumed the same
Telegram update_id, causing /menu callbacks to fire twice. Add a
shared dedup module backed by telegram_update_dedup table (300s TTL,
60s cleanup) with in-memory fallback, wired into both paths.

Polling launcher now skips startup when webhook is configured to
prevent dual-consumption at the source.

38 tests across webhook, menu keyboards, telegram_api, dedup guard,
and trend bot service.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-02 12:01:04 +08:00
OoO
75de76ac12 fix(momo): block EC404 auto-open with end-to-end URL guard
Some checks failed
CD Pipeline / deploy (push) Has been cancelled
- normalize URLs at write time (scheduler crawlers, routes) to drop
  javascript:/EC404/placeholder i_code (momo_/manual_/pchome_)
- add global click+auxclick guard in base.html and ewoooc_base.html
  that intercepts blocked MOMO URLs and redirects to safe i_code URL
- per-page dashboards reuse the same isLikelyMomoIcode validation
- /api/track_momo_link records blocked events for diagnosis
- ship sanitize_momo_urls.py to clean existing polluted DB rows

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-02 12:00:34 +08:00
OoO
026d0e7539 feat(reports): move monthly analysis to v2 shell
All checks were successful
CD Pipeline / deploy (push) Successful in 2m14s
2026-05-01 21:13:18 +08:00
OoO
d6782ee710 feat(ai): move recommendation page to v2 shell
All checks were successful
CD Pipeline / deploy (push) Successful in 2m13s
2026-05-01 21:08:44 +08:00
OoO
9b3e0a4565 feat(ai): move history page to v2 shell
All checks were successful
CD Pipeline / deploy (push) Successful in 2m19s
2026-05-01 21:06:17 +08:00
OoO
939ed5eef5 feat(ai): move intelligence page to v2 shell
All checks were successful
CD Pipeline / deploy (push) Successful in 2m18s
2026-05-01 21:03:19 +08:00
OoO
7d46ff9ba5 feat(competitor): persist match attempts
All checks were successful
CD Pipeline / deploy (push) Successful in 2m9s
2026-05-01 20:56:17 +08:00
OoO
c1f43b0ae4 fix(campaign): persist full crawl snapshots
All checks were successful
CD Pipeline / deploy (push) Successful in 2m22s
2026-05-01 20:48:28 +08:00
OoO
bb99dfeab6 feat(campaign): restore operations table signals
Some checks failed
CD Pipeline / deploy (push) Has been cancelled
2026-05-01 20:43:46 +08:00
OoO
4e853a233f perf(dashboard): speed up competitor overview
All checks were successful
CD Pipeline / deploy (push) Successful in 2m12s
2026-05-01 20:36:25 +08:00
OoO
b9d6186d68 feat(frontend): sync latest MOMO Pro prototype styling
All checks were successful
CD Pipeline / deploy (push) Successful in 2m18s
2026-05-01 20:32:23 +08:00