diff --git a/TODO_NEXT_STEPS.txt b/TODO_NEXT_STEPS.txt index ee9b9a9..e442431 100644 --- a/TODO_NEXT_STEPS.txt +++ b/TODO_NEXT_STEPS.txt @@ -4,6 +4,7 @@ ================================================================================ 【已完成】 + - 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 送出前會把 `
` / `
` / `
` 統一轉成換行,避免 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 traceability;API/UI 不讀 approval/Telegram token、不呼叫 LLM、不派送 Telegram、不開 DB、不寫檔、不產報表、不更新 review_state、不掛 scheduler。 @@ -139,7 +140,7 @@ - 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、不連外、不掛 scheduler;V10.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 rollback,V10.101 修正後成功 insert `momo/pchome/coupang/shopee` 四筆 seed;read-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`。 - - 注意:正式端 `/api/market_intel/seed_writer_cli_status?execute=true&platform=all` 仍回傳舊版 `approval_token_hint=APPROVED_MARKET_INTEL_SEED_WRITE_V1` 與固定 token gate 文案,與 main 已入庫的一次性環境 token hardening 不一致;下次正式白名單部署需優先同步 `services/market_intel/seed_writer_cli.py`、`services/market_intel/service.py`、`scripts/market_intel_seed_writer.py`,並 smoke 確認不再回吐 `approval_token_hint`。 + - 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、不連外、不掛 scheduler;UI 新增「既有資料橋接預覽」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。 @@ -201,7 +202,7 @@ - 測試:新增 `tests/test_market_intel_skeleton.py`,確認預設 flags 全關、adapter 不允許 network/write/scheduler,手動 discovery / candidate preview 預設不發 request,parser/scorer/confidence 診斷只輸出 JSON,UI 只使用 `fetch=false`,platform seed plan 只讀且需 gate。 【下次待辦】 - - 正式端 seed writer token-hardening drift:優先白名單同步 main 的一次性環境 token 版本,避免 API 暴露固定 approval token hint。 + - 下次市場情報 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 模式。 diff --git a/config.py b/config.py index cfb84a3..c61df27 100644 --- a/config.py +++ b/config.py @@ -320,7 +320,7 @@ YOUTUBE_API_KEY = os.getenv('YOUTUBE_API_KEY', '') # ========================================== # 系統版本與路徑 # ========================================== -SYSTEM_VERSION = "V10.322" +SYSTEM_VERSION = "V10.323" LOG_FILE_PATH = os.path.join(BASE_DIR, 'logs/system.log') public_url = PUBLIC_URL # 用於模板顯示 diff --git a/services/market_intel/seed_writer_cli.py b/services/market_intel/seed_writer_cli.py index ad4d46a..1b75019 100644 --- a/services/market_intel/seed_writer_cli.py +++ b/services/market_intel/seed_writer_cli.py @@ -356,6 +356,9 @@ def build_seed_writer_cli_plan( "approval_token_valid": approval_token_valid, "approval_env_var": APPROVAL_ENV_VAR, "approval_token_secret_configured": approval_token_secret_configured, + "api_reads_approval_token": False, + "api_executes_cli": False, + "api_writes_database": False, "ready_for_real_write": ready_for_real_write, "writes_executed": writes_executed, "would_write_database": bool(ready_for_real_write), diff --git a/tests/test_market_intel_skeleton.py b/tests/test_market_intel_skeleton.py index 232cc08..2349e66 100644 --- a/tests/test_market_intel_skeleton.py +++ b/tests/test_market_intel_skeleton.py @@ -16390,6 +16390,9 @@ def test_seed_writer_cli_status_blocks_real_write(): assert status["approval_token_valid"] is True assert status["approval_token_secret_configured"] is True assert "approval_token_hint" not in status + assert status["api_reads_approval_token"] is False + assert status["api_executes_cli"] is False + assert status["api_writes_database"] is False assert status["ready_for_real_write"] is False assert status["writes_executed"] is False assert status["would_write_database"] is False @@ -16441,6 +16444,9 @@ def test_seed_writer_cli_status_route_never_leaks_approval_token(monkeypatch): assert data["approval_token_present"] is False assert data["approval_token_valid"] is False assert data["approval_token_secret_configured"] is True + assert data["api_reads_approval_token"] is False + assert data["api_executes_cli"] is False + assert data["api_writes_database"] is False assert data["ready_for_real_write"] is False assert data["writes_executed"] is False assert data["would_write_database"] is False @@ -16490,6 +16496,9 @@ def test_seed_writer_cli_real_write_sqlite_upserts_seed_rows(): ).fetchall() assert status["mode"] == "seed_writer_cli_executed" + assert status["api_reads_approval_token"] is False + assert status["api_executes_cli"] is False + assert status["api_writes_database"] is False assert status["ready_for_real_write"] is True assert status["writes_executed"] is True assert status["would_write_database"] is True