From 7929868309d83be2464f923786520653c1cc6d08 Mon Sep 17 00:00:00 2001 From: Sean Date: Sun, 30 Aug 2026 22:41:14 +0800 Subject: [PATCH 01/12] rpb(orchestrator): add PLAN.md for trade-backtest autonomous run Bootstrap plan for 4-wave / 9-milestone autonomous run: - W1: PLAN.md (this), qa test runner, devops CI - W2: backend vercel.json fix, backend input validation, security audit - W3: frontend a11y/CSP, docs README/CHANGELOG/AGENTS - W4: orchestrator final reports Includes AGENTS.md auto-bootstrap from repo-builder context layer (will be replaced by M8 with real content). --- AGENTS.md | 28 ++++++++++++ PLAN.md | 126 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 154 insertions(+) create mode 100644 AGENTS.md create mode 100644 PLAN.md diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..b776a4b --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,28 @@ +# trade-backtest + +> 由 `repo-builder` 自動補建的 AGENTS.md 骨架(v2.0)。 +> 若這份檔已存在則**不會覆寫**;手動修改後 commit 即可。 + +## 目標 + +- <一句話描述這個 repo 要解決什麼問題、最終要交付什麼> + +## 避免 + +- <列出已知地雷、技術選型限制、不要踩的 pattern> +- <列出與其他專案的邊界> + +## (選填)技術棧與指令 + +- 主要語言:javascript +- 框架:(無) +- Test runner:npm test +- Verify commands: +- `node --check lightweight-charts.4.1.0.js signal-monitor.js api/klines.js api/fundamental.js` + +## 偵測到的備註 + +- 找到 PRD/SPEC,目標與範圍有書面紀錄 +- 沒有偵測到任何測試,目標可加上最低門檻測試 +- 偵測到 deploy target: vercel +- cloned_to:/Users/sean/Documents/Agent space/prompts/trade-backtest/.clone diff --git a/PLAN.md b/PLAN.md new file mode 100644 index 0000000..948e1f4 --- /dev/null +++ b/PLAN.md @@ -0,0 +1,126 @@ +# Plan: trade-backtest + +> 為什麼這樣排(<= 200 字中文):先把「能驗證」做到位(W1 補 test runner + CI + 規劃書),再修掉「實際會壞」的硬傷(W2:vercel.json 找不到 SPEC.md、API 沒有 input validation、secrets/CORS 體檢),接著做「產品面」的低風險打磨(W3:index.html a11y/mobile/CSP 與 README/CHANGELOG/AGENTS),最後 orchestrator 收尾(W4:build report + 反思 + followup)。全程嚴守:純 JS、無 npm、不動 PRD/SPEC §1-§9、rpb 前綴、SHA-pinned actions、verify command 不變。每個 milestone 範圍 ≤ 150 LOC,verify < 5 分鐘。 + +## Wave 1: 規劃 + 測試 + CI 基線 + +### Milestone M1: 寫出 PLAN.md(自身) +- owner: orchestrator +- scope: `.clone/PLAN.md` +- verify: `test -f .clone/PLAN.md && wc -l .clone/PLAN.md` +- est. LOC: 100 +- notes: 由當下 orchestrator subagent 自己完成;parent driver 收到後會 commit `rpb(orchestrator): add PLAN.md for trade-backtest`。這一步不跑 `node --check`,因為沒有改任何 JS。 + +### Milestone M2: 補上純 Node、無 npm 的 test runner + signal-monitor 純函式 smoke tests +- owner: qa +- scope: `tests/run.js`(新增)、`tests/signal-monitor.test.js`(新增,3-5 個 case) +- verify: `node tests/run.js` 全部 case PASS;同時 `node --check lightweight-charts.4.1.0.js signal-monitor.js api/klines.js api/fundamental.js` 仍 exit 0 +- est. LOC: 120 +- notes: 跑 `signal-monitor.js` 內的純函式:`calculateMA`(不足 period 回 null;滿足 period 回正確均值)、`calculateRSI`(全漲 → 100、全跌 → 0/100 邊界)、`calculateMACD`(histogram 對齊長度)、`detectSignals`(golden cross / death cross / RSI 極端 / MACD 交叉 至少 4 個 case)。test runner 用 stdlib `assert` + 自寫 minimal harness(assertEqual / assertDeepEqual + summary),無 npm。為了隔離純函式,QA 必須讀原始檔後透過 `require('../signal-monitor.js')` 拿到 export;若 signal-monitor.js 的 module.exports 不夠,需要 backend 同步 export 該純函式——已驗證 `module.exports = { monitorSignals, detectSignals }` 在檔案末尾,目前 `calculateMA/calculateRSI/calculateMACD` **未 export**,所以 M2 的子任務包含把這 3 個 helper 加進 `module.exports`(小、純、不改行為)。若發現需要動 `signal-monitor.js`,則後端 M5 也要對齊(驗證後者不會破壞 M2 已有的測試)。 + +### Milestone M3: GitHub Actions CI(SHA-pinned)跑 node --check + test runner +- owner: devops +- scope: `.github/workflows/ci.yml`(新增) +- verify: YAML parse:`python3 -c "import yaml,sys; yaml.safe_load(open('.github/workflows/ci.yml'))"`;同時 `node --check lightweight-charts.4.1.0.js signal-monitor.js api/klines.js api/fundamental.js` 仍 exit 0(CI workflow 不影響 source) +- est. LOC: 35 +- notes: workflow 必須用 SHA pinned actions:`actions/checkout@`、`actions/setup-node@`。Node 版本:`node-version: '20'`(klines.js 用 global fetch,fundamental.js 用 node-fetch — 後者需在 CI 內偵測,若沒裝須在 followup 標出;M3 不解 fundamental.js 的 node-fetch 缺漏,那屬於 W2 後端範圍)。CI triggers:`push:branches:[master,feat/**,fix/**,chore/**,docs/**,test/**]` 與 `pull_request`。Cache 用 `setup-node` 的 `cache:` 參數。**注意**:本 repo 無 package.json,因此不跑 `npm ci`。 + +## Wave 2: 真實的後端 + 安全硬傷 + +### Milestone M4: 修 `vercel.json` SPEC.md → PRD/SPEC.md 路徑錯誤 +- owner: backend +- scope: `vercel.json`(單一檔) +- verify: `node -e "JSON.parse(require('fs').readFileSync('vercel.json','utf8'))"` 仍 exit 0;`node --check lightweight-charts.4.1.0.js signal-monitor.js api/klines.js api/fundamental.js` 仍 exit 0;`test -f PRD/SPEC.md` 仍 true +- est. LOC: 5 +- notes: 把 `vercel.json` 中 `"src": "SPEC.md"` 改為 `"src": "PRD/SPEC.md"`(這條 build entry 才會找到實際檔案,否則 Vercel deploy 會 404)。其他 entry 維持不動;不改 routes;不改 `@vercel/node` / `@vercel/static` 設定。 + +### Milestone M5: 補 `/api/klines` 與 `/api/fundamental` 的 input validation + 統一 fetch helper +- owner: backend +- scope: `api/klines.js`、`api/fundamental.js` +- verify: `node --check api/klines.js api/fundamental.js signal-monitor.js` exit 0;`node tests/run.js` 仍 PASS(M2 寫的測試);同時新加 1 個 manual smoke:`node -e "require('./api/fundamental.js')" && node -e "require('./api/klines.js')"`(僅載入,不打網路) +- est. LOC: 70 +- notes: + 1. `api/klines.js`:新增 `validateSymbol()`(reject 非英數、> 20 字元、`/api/../` 路徑穿越);reject 已知的 SSRF 探測(symbol 含 `://` 或 `..`);把 `interval` 限制為白名單 `['1m','5m','15m','1h','4h','1d','1w']`;`days` 已 clamp 到 [1, 2190],保留。 + 2. `api/fundamental.js`:symbol 同樣白名單 + 長度限制;統一改用 Node 18+ global `fetch`(與 `klines.js` 一致),把 `const fetch = require('node-fetch')` 改為「若 Node < 18 才退回 node-fetch」——但因為這 repo 沒 package.json,**不能** import node-fetch。最小解:移除 `node-fetch`,全程用 global `fetch`;若 build/runtime 環境 < Node 18,把需求寫進 FOLLOWUP.md。 + 3. 兩個檔案的 handler 都要在 400 / 500 路徑明確分開(目前 `klines.js` 對 final fallback 用 `200 { success: false }`,這屬於既有行為,不在本次 scope;本 milestone 只加 symbol/interval validation,不改既有 happy-path payload schema)。 + 4. 若 QA 的 M2 已經改了 `signal-monitor.js` 的 `module.exports` 來暴露純函式,這個 milestone 確認改動不破壞現有 export signature。 + +### Milestone M6: Secrets / SSRF / CORS / XSS audit + SECURITY_FINDINGS.md +- owner: security +- scope: 跨檔 audit(不改 production code 行為)+ 新增 `SECURITY_FINDINGS.md` +- verify: `grep -rEn "(sk-[A-Za-z0-9]{16,}|AKIA[0-9A-Z]{16}|ghp_[A-Za-z0-9]{20,})" . --include='*.js' --include='*.html' --include='*.json' --include='*.md'` exit 0(無 match);`node --check lightweight-charts.4.1.0.js signal-monitor.js api/klines.js api/fundamental.js` 仍 exit 0;`test -f SECURITY_FINDINGS.md` +- est. LOC: 60 +- notes: + - 不修 production code,只報告(修補歸各 owner)。 + - 必查:① `config.json.example` 是否含 placeholder(已確認為空字串,OK);② `index.html` 的 `innerHTML =` 是否會插入 user input(grep 結果目前都是 template literal 內部組字,非外部輸入,標 low);③ `api/klines.js` 的 `Access-Control-Allow-Origin: '*'`(公開資料 API,OK,但若未來加 credentials 需修);④ Telegram 訊息目前用 HTML parse_mode,**沒有 escape**,symbol 可能含 `<>`——標 medium 寫進 findings;⑤ `vercel.json` SPEC.md 路徑(已被 M4 修掉,本 milestone 僅 reference);⑥ 確認 `.gitignore` 已擋下 `.env`、`config.json`、`signal_log.json`(已確認 OK)。 + - 額外:在 `SECURITY_FINDINGS.md` 列出 medium/low finding 各一條 actionable,但 **不修**,由對應 owner 後續處理(避免 scope creep)。 + +## Wave 3: 前端 + 文件 + +### Milestone M7: index.html a11y / CSP / mobile 低風險修補 +- owner: frontend +- scope: `index.html` +- verify: `node --check lightweight-charts.4.1.0.js signal-monitor.js api/klines.js api/fundamental.js` exit 0;`python3 -c "from html.parser import HTMLParser; HTMLParser().feed(open('index.html').read())"` exit 0(HTML stack balance);`grep -c '` 加 ``(CSP 第一版,scope 限定,後續可微調)。 + 2. 給所有 icon-only button 補 `aria-label`(grep 後看 `