[V10.323] 明確標示 seed writer API token 邊界
All checks were successful
CD Pipeline / deploy (push) Successful in 1m3s

This commit is contained in:
OoO
2026-05-20 12:37:31 +08:00
parent 4d62731730
commit a4590db8ba
4 changed files with 16 additions and 3 deletions

View File

@@ -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 送出前會把 `<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。
@@ -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、不連外、不掛 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`。
- 注意:正式端 `/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、不連外、不掛 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。
@@ -201,7 +202,7 @@
- 測試:新增 `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 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 模式。

View File

@@ -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 # 用於模板顯示

View File

@@ -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),

View File

@@ -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