Add trader mainline surface audit
This commit is contained in:
+2
-2
@@ -831,11 +831,11 @@ Automation execution-layer PXX remains closed and its known scope stays frozen.
|
||||
- Existing-UI i18n polish passed on 2026-05-20 without adding product features: hardened phrase replacement so short words like `no` no longer corrupt larger English words such as `not` / `enough`, then optimized Chinese labels for existing Trader Mode / duty / chart bridge / R2 evidence / runtime workbench surfaces. Remote browser audit on `/trader-mode?audit=20260520e#trader-mode` confirmed no `否t` / `e否ugh` corruption, no old English labels such as `Bridge Status`, `Exact Candle Source`, `Use Today`, `Paper Tickets`, or `Decision Support Ready`, and reduced visible English-remnant audit count from `3396` before the fix to `881` after the fix; the remaining items are mostly symbols/session names/ICT tokens/internal status keys. Validation passed `node --check src/web/i18n.js`, 27 focused static/read-only/operator tests, secret static checks, script static checks, full unit discovery (`789` tests), `git diff --check` with only LF/CRLF warnings, deploy smoke over 11 endpoints, `run_remote_ops_smoke.py`, `run_readonly_live_analysis_smoke.py`, and gstack browser console check with no errors. Evidence screenshot saved at `output/playwright/i18n-existing-ui-polish-zh-1366x768.png`. No change was made to `execution_allowed`, `decision_support_ready`, `real_live_ready`, risk governor, trust bucket, or operator confirmation protocol.
|
||||
- Existing-UI i18n/R2 gate polish follow-up passed on 2026-05-20 without adding product features: expanded the existing Chinese translation map for live-readiness, launch-readiness, shadow/paper validation, runtime states, OKX sandbox preflight labels, and Trader Mode first-screen wording. Remote browser audit on `/trader-mode?audit=20260520k#trader-mode` confirmed `lang=zh-CN`, no `为什么不交易不交易`, no `下一步观察观察候选`, no `操作员反馈 count`, and no old English labels such as `Auto refresh`, `All Trust`, `Incident Journal`, `Maintenance Rollup`, `Plan Context`, `Model Trust`, `Live Readiness`, or `Launch Readiness`; the remaining English-token count in the active Trader Mode view is `13`, mostly `English`, `ai-ict`, timezone/profile names, strategy codes, and feedback enum values. Trader Mode R2 evidence display now follows `shadow_paper_validation_summary.failed_criteria`, so the evidence window no longer says operator feedback is complete while the canonical shadow validation gate still requires more samples. Current live evidence is still collecting: `operator_feedback_count=3/5`, `paper_ticket_count=0`, `paper_execution_count=0`, and `weekly_review_entry_count=0`. Validation passed focused i18n/operator/static tests, secret static checks, script static checks, full unit discovery (`790` tests), deploy smoke over 11 endpoints, `run_remote_ops_smoke.py`, `run_readonly_live_analysis_smoke.py`, and gstack browser console check with no errors. Evidence screenshot saved at `output/playwright/i18n-existing-ui-polish-zh-followup-1366x768.png`. No change was made to `execution_allowed`, `decision_support_ready`, `real_live_ready`, risk governor, trust bucket, or operator confirmation protocol.
|
||||
- Session Focus Chinese dynamic-label follow-up passed on 2026-05-20 without adding product features: fixed the existing i18n layer for dynamic session-focus cards so session names and lower-case backend labels now render in Chinese (`ASIA`, `LONDON`, `NY_AM`, `NY_LUNCH`, `NY_PM`, `status`, `window`, `candidates`, `executable`, `open executions`, `alerts`, `recommendation`, `action hint`, `incomplete`, `closed`, `observe`, `avoid`, `review_alerts`, `avoid_new_risk`). Remote browser audit on `/trader-mode?i18n=20260520-session#session-focus` confirmed `lang=zh-CN`, `active=session-focus`, no English leftovers from the reported list, and visible Chinese replacements such as `亚洲盘`, `纽约下午盘`, `状态`, `时间窗口`, `候选数`, `可执行数`, `未平仓执行`, `提醒数`, `建议`, `动作提示`, `观察 @ 无`, `回避 @ 30.0`, `回避新增风险`, and `复核提醒`; console errors were empty. Validation passed `node --check src/web/i18n.js`, focused static/operator/read-only tests, secret static checks, script static checks, full unit discovery (`790` tests), deploy smoke over 11 endpoints, `run_remote_ops_smoke.py`, and `run_readonly_live_analysis_smoke.py`. Evidence screenshot saved at `output/playwright/i18n-session-focus-zh-1366x768.png`. No change was made to `execution_allowed`, `decision_support_ready`, `real_live_ready`, risk governor, trust bucket, or operator confirmation protocol.
|
||||
- Current assisted-analysis next gate: keep R1/R2 focused on `decision_support_ready` trust/sample/quality evidence and shadow/paper/operator feedback collection. OKX trade-permission sandbox smoke is deferred until the project explicitly re-enters execution adapter or real-trading preparation.
|
||||
- Current assisted-analysis next gate: S1 mainline deletion readiness audit is complete via `docs/AI_ICT_主线裁剪审计_S1_2026-05-21_v1.md` and `scripts/audit_trader_mainline_surfaces.py`. The top navigation is already reduced to Trader Cockpit / Strategy Backtest / Trading Plan / Journal / System Ops; remaining non-mainline sections are classified under System Ops, Research Only, or Deprecated / Deferred Execution, with no physical deletion allowed yet. Keep R1/R2 focused on `decision_support_ready` trust/sample/quality evidence and shadow/paper/operator feedback collection. OKX trade-permission sandbox smoke is deferred until the project explicitly re-enters execution adapter or real-trading preparation.
|
||||
|
||||
## Exact Next Step
|
||||
|
||||
Use `docs/AI_ICT_实盘辅助分析决策助手ICT主线开发方案_2026-05-21_v1.md` as the next active development anchor. Continue with S1 mainline deletion readiness audit: scan all non-mainline trader-facing routes, sidebar sections, API endpoints, frontend panels, and tests; classify each as `Mainline`, `System Ops`, `Research Only`, `Deprecated`, or `Delete Candidate`; do not physically delete shared or diagnostic code until dependency, API usage, test coverage, rollback, and remote smoke impact are clear. Every follow-up slice must map to `docs/ICT交易全书_出版终校版.md` and the mandatory chain `Range / Draw / Location -> Liquidity / Sweep / Inducement / Path -> Displacement / MSS / FVG / Retest / Session -> backtest evidence -> pre-market plan -> intraday unique focus or no-trade reason -> journal / study-notes feedback`. Do not restart external-context/archive/digest long-tail work, do not create order-submission features, and do not fabricate R2 paper samples. Keep `execution_allowed`, `decision_support_ready`, `real_live_ready`, risk governor, trust bucket, and operator confirmation protocol unchanged.
|
||||
Use `docs/AI_ICT_实盘辅助分析决策助手ICT主线开发方案_2026-05-21_v1.md` and `docs/AI_ICT_主线裁剪审计_S1_2026-05-21_v1.md` as the active anchors. Continue with S2 ICT canonical taxonomy / rulebook registry: define the book-backed concepts required by every Trader Cockpit focus, Strategy Backtest result, Trading Plan item, and Journal note, then add focused validation that prevents trader-facing output from using unclassified internal reason buckets without the mandatory `Range / Draw / Location -> Liquidity / Sweep / Inducement / Path -> Displacement / MSS / FVG / Retest / Session -> backtest evidence -> pre-market plan -> intraday unique focus or no-trade reason -> journal / study-notes feedback` mapping. Do not restart external-context/archive/digest long-tail work, do not create order-submission features, do not physically delete S1 deprecated surfaces yet, and do not fabricate R2 paper samples. Keep `execution_allowed`, `decision_support_ready`, `real_live_ready`, risk governor, trust bucket, and operator confirmation protocol unchanged.
|
||||
|
||||
## Validation Commands Used Recently
|
||||
|
||||
|
||||
@@ -933,8 +933,8 @@
|
||||
- [x] Trader mainline Step 3 Strategy Backtest productization: added read-only `/trading/backtests`, Strategy Backtest workbench controls, latest-run summary, quality gate explanation, R metrics, equity curve, top sessions, failure reasons, recent run list, Chinese labels for backtest gate reasons, and resilient candle/backtest failure fallback; full unit (`791`), deploy smoke, remote ops smoke, readonly live smoke, remote backtest endpoint smoke, and browser audit passed
|
||||
- [x] Trader mainline Step 4 cockpit recompression implemented/deployed: under the hard ICT book mainline gate, Trader Cockpit first screen now reduces to `Now / Reason / Wait / Risk / Historical Edge / Boundary` and uses latest Strategy Backtest evidence without changing any execution/readiness gate; deploy smoke, remote ops smoke, remote backtest field smoke, browser QA, and the recovered read-only launch smoke passed with `ready_for_readonly_live_analysis=true`, `must_not_trade=true`, `trade_permission_required=false`, and no submit/cancel/live execution calls
|
||||
- [x] Created next-stage ICT mainline development anchor: `docs/AI_ICT_实盘辅助分析决策助手ICT主线开发方案_2026-05-21_v1.md`, binding all future work to `docs/ICT交易全书_出版终校版.md`, read-only assisted analysis, Strategy Backtest, Trading Plan, Trader Cockpit, Journal, and System Ops separation
|
||||
- [ ] Trader mainline Step 5 deletion readiness audit: scan non-mainline trader-facing surfaces for dependency/API/test coverage before any code-level deletion; keep diagnostics under `System Ops` unless proven removable
|
||||
- [ ] S1 mainline deletion readiness audit under the new plan: classify routes/sidebar/API/frontend panels/tests as `Mainline`, `System Ops`, `Research Only`, `Deprecated`, or `Delete Candidate`, then hide/migrate before considering physical deletion
|
||||
- [x] Trader mainline Step 5 deletion readiness audit: added `scripts/audit_trader_mainline_surfaces.py`, classified 5 top-nav targets, 19 workspace sections, 80 API routes, 43 frontend API references, and 108 test endpoint references before any deletion; diagnostics stay under `System Ops`
|
||||
- [x] S1 mainline deletion readiness audit under the new plan: created `docs/AI_ICT_主线裁剪审计_S1_2026-05-21_v1.md`; current top navigation is compliant, Research Only and Deprecated/Deferred Execution surfaces are documented, and physical deletion remains blocked until dependency/API/test/remote-smoke impact is proven safe
|
||||
- [ ] S2 ICT canonical taxonomy/rulebook registry: require every Trader Cockpit focus, Strategy Backtest result, Trading Plan item, and Journal note to map to the book chain
|
||||
- [ ] S3/S4 follow-up: make Trading Plan a hard upstream gate for `Review Now`, then deepen Strategy Backtest so quality-gate failure blocks weak setups from live focus
|
||||
- [ ] R2 paper-ticket sample gate is waiting on a real executable candidate; do not fabricate paper tickets from blocked candidates
|
||||
|
||||
@@ -0,0 +1,216 @@
|
||||
# AI_ICT 主线裁剪审计 S1 2026-05-21 v1
|
||||
|
||||
## 0. 审计边界
|
||||
|
||||
本审计执行 `docs/AI_ICT_实盘辅助分析决策助手ICT主线开发方案_2026-05-21_v1.md` 的 S1。
|
||||
|
||||
目标不是立刻删除代码,而是先把交易员主线、System Ops、研究保留面、延期/废弃执行面分清楚,避免继续把复杂功能塞回盘中主界面。
|
||||
|
||||
硬边界保持不变:
|
||||
|
||||
```text
|
||||
execution_allowed=false
|
||||
decision_support_ready=false
|
||||
real_live_ready=false
|
||||
must_not_trade=true
|
||||
trade_permission_required=false
|
||||
submit_cancel_or_live_execution_called=false
|
||||
```
|
||||
|
||||
## 1. 审计方法
|
||||
|
||||
新增可重复扫描脚本:
|
||||
|
||||
```bash
|
||||
python scripts/audit_trader_mainline_surfaces.py --output-json
|
||||
```
|
||||
|
||||
扫描范围:
|
||||
|
||||
- `src/web/index.html` 的顶层导航、workspace sections、System Ops links。
|
||||
- `src/web/app.js` 与 `src/web/trader_mode.js` 的 `fetchJson` / `postJson` 前端 API 引用。
|
||||
- `src/api/server.py` 的显式 API routes。
|
||||
- `tests/unit/test_*.py` 中的 endpoint 测试引用。
|
||||
|
||||
本轮扫描结果:
|
||||
|
||||
```text
|
||||
top nav targets: 5
|
||||
workspace sections: 19
|
||||
system ops targets: 14
|
||||
api routes: 80
|
||||
frontend api references: 43
|
||||
test endpoint references: 108
|
||||
```
|
||||
|
||||
分类计数:
|
||||
|
||||
```text
|
||||
workspace sections:
|
||||
- Mainline: 4
|
||||
- System Ops: 10
|
||||
- Research Only: 3
|
||||
- Deprecated: 2
|
||||
|
||||
api routes:
|
||||
- Mainline: 16
|
||||
- System Ops: 26
|
||||
- Research Only: 33
|
||||
- Deprecated: 5
|
||||
|
||||
frontend api references:
|
||||
- Mainline: 12
|
||||
- System Ops: 20
|
||||
- Research Only: 9
|
||||
- Deprecated: 2
|
||||
```
|
||||
|
||||
## 2. 顶层导航结论
|
||||
|
||||
当前顶层导航已经符合新方案:
|
||||
|
||||
| 导航入口 | 分类 | 结论 |
|
||||
| --- | --- | --- |
|
||||
| `trader-mode` / Trader Cockpit | Mainline | 保留,盘中唯一首屏 |
|
||||
| `strategy-backtest` / Strategy Backtest | Mainline | 保留,验证 ICT setup 是否有历史优势 |
|
||||
| `trading-plan` / Trading Plan | Mainline | 保留,后续作为 `Review Now` 的上游硬门 |
|
||||
| `journal` / Journal | Mainline | 保留,真实观察与盘后复盘入口 |
|
||||
| `system-ops` / System Ops | System Ops | 保留,承接复杂诊断与旧功能 |
|
||||
|
||||
结论:顶层菜单不需要继续扩展;后续新增功能默认不得进入顶层导航。
|
||||
|
||||
## 3. Workspace Section 分类
|
||||
|
||||
| Section | 分类 | S1 决策 |
|
||||
| --- | --- | --- |
|
||||
| `trader-mode` | Mainline | 保留,继续压缩为 ICT fast read |
|
||||
| `strategy-backtest` | Mainline | 保留,后续深化 book-rule quality gate |
|
||||
| `trading-plan` | Mainline | 保留,后续重构为书本顺序计划表 |
|
||||
| `journal` | Mainline | 保留,后续对齐 Study Notes / Journal 闭环 |
|
||||
| `system-ops` | System Ops | 保留,复杂能力的唯一入口 |
|
||||
| `overview` | System Ops | 保留在 System Ops,不能回到主线 |
|
||||
| `trading-status` | System Ops | 保留为诊断,不作为交易指令 |
|
||||
| `runtime-supervisor` | System Ops | 保留为运行时诊断 |
|
||||
| `decision-packet` | System Ops | 保留为审计材料,不作为盘中主屏 |
|
||||
| `readiness` | System Ops | 保留,显示 readiness/trust 边界 |
|
||||
| `session-focus` | System Ops | 保留为 ICT session 辅助诊断,后续可被 Trading Plan 引用 |
|
||||
| `intraday-candidates` | System Ops | 保留为候选调试,不直接给交易员主屏 |
|
||||
| `alerts` | System Ops | 保留为运营/告警质量诊断 |
|
||||
| `candles` | System Ops | 保留为只读行情诊断 |
|
||||
| `decision-assistant` | Research Only | 冻结主线扩张,仅作为研究/内部审计面 |
|
||||
| `visual-reviews` | Research Only | 冻结主线扩张,不能替代书本链路 |
|
||||
| `operator-console` | Research Only | 保留为内部研究/操作面,不进入主线 |
|
||||
| `execution-tickets` | Deprecated | 当前不做交易,保留代码但不得突出展示为交易员主功能 |
|
||||
| `position-management` | Deprecated | 当前不做实盘持仓管理,保留代码但不得进入主线 |
|
||||
|
||||
本轮不做物理删除。原因:`Deprecated` 不等于“确认无依赖”,仍需后续检查动态路由、测试覆盖和远端 smoke 影响。
|
||||
|
||||
## 4. API 分类结论
|
||||
|
||||
### 4.1 Mainline API
|
||||
|
||||
这些 API 直接服务 Trader Cockpit、Strategy Backtest、Trading Plan、Journal 或只读主线:
|
||||
|
||||
- `/health`
|
||||
- `/candles`
|
||||
- `/trading/backtests`
|
||||
- `/trading/plans`
|
||||
- `/trading/plans/latest`
|
||||
- `/trading/plans/generate`
|
||||
- `/trading/review-packet`
|
||||
- `/trading/operator-notes`
|
||||
- `/trading/shadow-paper/observe`
|
||||
- `/trading/shadow-paper-validation`
|
||||
- `/trading/journal`
|
||||
- `/trading/journal/summary`
|
||||
- `/trading/journal/generate`
|
||||
- `/trading/research/weekly-review`
|
||||
- `/trading/launch-readiness`
|
||||
|
||||
结论:保留,后续必须全部映射到《ICT交易全书》的主线字段。
|
||||
|
||||
### 4.2 System Ops API
|
||||
|
||||
这些 API 保留用于运行时、数据、候选、告警和只读可用性诊断:
|
||||
|
||||
- `/trading/runtime-status`
|
||||
- `/trading/runtime-watchdog`
|
||||
- `/trading/runtime-incidents`
|
||||
- `/trading/runtime/run-once`
|
||||
- `/trading/maintenance-summary`
|
||||
- `/trading/unattended-harness`
|
||||
- `/trading/live-readiness`
|
||||
- `/trading/broker-state`
|
||||
- `/trading/market-state`
|
||||
- `/trading/trust-score`
|
||||
- `/trading/session-view`
|
||||
- `/trading/candidates`
|
||||
- `/trading/decision-packet`
|
||||
- `/trading/alerts/*`
|
||||
- `/trading/watch/run`
|
||||
|
||||
结论:保留在 System Ops,不得作为交易员主线功能继续膨胀。
|
||||
|
||||
### 4.3 Research Only API
|
||||
|
||||
这些 API 来自历史 archive、workflow、external context、visual watch、research council、training 等长尾能力:
|
||||
|
||||
- `/trading/archive-baselines`
|
||||
- `/trading/assistant-focus`
|
||||
- `/trading/external-context-surface-history`
|
||||
- `/trading/research-council/*`
|
||||
- `/trading/visual-watch/*`
|
||||
- `/trading/workflow-archive/*`
|
||||
- `/training/*`
|
||||
|
||||
结论:冻结主线扩张。只有当某个能力能明确服务 `Range / Draw / Liquidity / MSS / FVG / Backtest / Plan / Journal` 链路时,才允许被重新纳入主线。
|
||||
|
||||
### 4.4 Deprecated / Deferred Execution API
|
||||
|
||||
这些 API 带有执行、票据、持仓、OKX sandbox 或 reconciliation 语义:
|
||||
|
||||
- `/live-operation-audits`
|
||||
- `/trading/okx-sandbox-preflight`
|
||||
- `/trading/reconcile`
|
||||
- `/trading/executions`
|
||||
- `/trading/tickets`
|
||||
- `/trading/candidates/{id}/build-ticket`
|
||||
|
||||
结论:
|
||||
|
||||
- 当前只做实盘辅助分析,不做交易。
|
||||
- 这些 API 不得进入 Trader Cockpit / Strategy Backtest / Trading Plan / Journal 主线。
|
||||
- 代码暂时不删,保留在 System Ops / deferred execution 区域,等待用户明确进入执行阶段后再处理。
|
||||
|
||||
## 5. 删除准备结论
|
||||
|
||||
本轮没有发现可以立即物理删除且零风险的文件或 API。
|
||||
|
||||
原因:
|
||||
|
||||
- 多数旧能力仍有测试覆盖和前端引用。
|
||||
- `execution-tickets` / `position-management` 虽然不属于当前阶段,但仍和 R2 paper / future execution evidence 历史代码交织。
|
||||
- `archive` / `workflow` / `external context` 虽偏离主线,但大量 API 与 operator workspace 测试仍覆盖,直接删除风险高。
|
||||
- 当前最重要的是防止它们回到交易员主界面,而不是为了“干净”破坏已有远端 smoke。
|
||||
|
||||
## 6. 后续裁剪规则
|
||||
|
||||
后续任何裁剪必须按以下顺序:
|
||||
|
||||
1. 先确认是否服务《ICT交易全书》主线。
|
||||
2. 不服务主线但服务运行诊断的,迁到 System Ops。
|
||||
3. 不服务主线且只是研究长尾的,标记 Research Only 并冻结扩张。
|
||||
4. 带执行/下单/票据/持仓语义的,在当前阶段标记 Deprecated / Deferred Execution。
|
||||
5. 只有同时满足“无主线价值、无 System Ops 价值、无测试依赖、无前端引用、无远端 smoke 依赖、可回滚”时,才进入 Delete Candidate。
|
||||
|
||||
## 7. 下一步
|
||||
|
||||
S1 审计已经完成。下一步进入 S2:
|
||||
|
||||
```text
|
||||
ICT canonical taxonomy / rulebook registry
|
||||
```
|
||||
|
||||
S2 目标是建立统一书本模型字典,让 Trader Cockpit focus、Strategy Backtest result、Trading Plan item、Journal note 都必须映射到《ICT交易全书》的固定链路。
|
||||
|
||||
下一步不应继续做 external context、archive、workflow、digest 长尾,也不应做 OKX trade permission / submit / cancel / fills。
|
||||
@@ -0,0 +1,326 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
from collections import Counter, defaultdict
|
||||
import json
|
||||
from pathlib import Path
|
||||
import re
|
||||
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
INDEX_HTML = ROOT / "src" / "web" / "index.html"
|
||||
APP_JS = ROOT / "src" / "web" / "app.js"
|
||||
TRADER_MODE_JS = ROOT / "src" / "web" / "trader_mode.js"
|
||||
API_SERVER = ROOT / "src" / "api" / "server.py"
|
||||
TESTS_DIR = ROOT / "tests" / "unit"
|
||||
|
||||
MAINLINE_SECTION_IDS = {
|
||||
"trader-mode",
|
||||
"strategy-backtest",
|
||||
"trading-plan",
|
||||
"journal",
|
||||
}
|
||||
|
||||
SYSTEM_OPS_SECTION_IDS = {
|
||||
"system-ops",
|
||||
"overview",
|
||||
"trading-status",
|
||||
"runtime-supervisor",
|
||||
"decision-packet",
|
||||
"readiness",
|
||||
"session-focus",
|
||||
"intraday-candidates",
|
||||
"alerts",
|
||||
"candles",
|
||||
}
|
||||
|
||||
RESEARCH_ONLY_SECTION_IDS = {
|
||||
"decision-assistant",
|
||||
"operator-console",
|
||||
"visual-reviews",
|
||||
}
|
||||
|
||||
DEPRECATED_SECTION_IDS = {
|
||||
"execution-tickets",
|
||||
"position-management",
|
||||
}
|
||||
|
||||
MAINLINE_ENDPOINT_PREFIXES = (
|
||||
"/health",
|
||||
"/candles",
|
||||
"/trading/backtests",
|
||||
"/trading/plans",
|
||||
"/trading/review-packet",
|
||||
"/trading/operator-notes",
|
||||
"/trading/shadow-paper",
|
||||
"/trading/shadow-paper-validation",
|
||||
"/trading/journal",
|
||||
"/trading/research/weekly-review",
|
||||
"/trading/launch-readiness",
|
||||
)
|
||||
|
||||
SYSTEM_OPS_ENDPOINT_PREFIXES = (
|
||||
"/trading/broker-state",
|
||||
"/trading/market-state",
|
||||
"/trading/runtime",
|
||||
"/trading/maintenance-summary",
|
||||
"/trading/unattended-harness",
|
||||
"/trading/trust-score",
|
||||
"/trading/session-view",
|
||||
"/trading/candidates",
|
||||
"/trading/decision-packet",
|
||||
"/trading/alerts",
|
||||
"/trading/live-readiness",
|
||||
)
|
||||
|
||||
RESEARCH_ONLY_ENDPOINT_PREFIXES = (
|
||||
"/trading/archive-baselines",
|
||||
"/trading/assistant-focus",
|
||||
"/trading/external-context",
|
||||
"/trading/research-council",
|
||||
"/trading/visual-watch",
|
||||
"/trading/workflow-archive",
|
||||
"/training",
|
||||
)
|
||||
|
||||
DEPRECATED_ENDPOINT_PREFIXES = (
|
||||
"/live-operation-audits",
|
||||
"/trading/okx-sandbox-preflight",
|
||||
"/trading/reconcile",
|
||||
"/trading/executions",
|
||||
"/trading/tickets",
|
||||
)
|
||||
|
||||
ROUTE_RE = re.compile(r'if method == "([A-Z]+)" and path == "([^"]+)"')
|
||||
SECTION_RE = re.compile(
|
||||
r'data-workbench-section="([^"]+)"[^>]*data-workbench-label="([^"]+)"',
|
||||
re.MULTILINE,
|
||||
)
|
||||
NAV_RE = re.compile(r'data-workbench-target="([^"]+)"[^>]*>([^<]+)</button>')
|
||||
SYSTEM_OPS_RE = re.compile(r'data-system-ops-target="([^"]+)"[^>]*>([^<]+)</button>')
|
||||
FRONTEND_ENDPOINT_RE = re.compile(
|
||||
r"(?:fetchJson|postJson)\(\s*(?:`([^`]+)`|'([^']+)'|\"([^\"]+)\")"
|
||||
)
|
||||
TEST_ENDPOINT_RE = re.compile(
|
||||
r"['\"](/(?:health|candles|trader-mode|static|live-operation-audits|training|trading)[^'\"]*)['\"]"
|
||||
)
|
||||
|
||||
|
||||
def normalize_endpoint(raw: str) -> str:
|
||||
endpoint = raw.split("?", 1)[0].strip()
|
||||
endpoint = re.sub(r"\$\{[^}]+\}", "{expr}", endpoint)
|
||||
endpoint = re.sub(r"/\d+(?=/|$)", "/{id}", endpoint)
|
||||
endpoint = endpoint.rstrip("/")
|
||||
return endpoint or raw
|
||||
|
||||
|
||||
def classify_section(section_id: str) -> str:
|
||||
if section_id in MAINLINE_SECTION_IDS:
|
||||
return "Mainline"
|
||||
if section_id in SYSTEM_OPS_SECTION_IDS:
|
||||
return "System Ops"
|
||||
if section_id in RESEARCH_ONLY_SECTION_IDS:
|
||||
return "Research Only"
|
||||
if section_id in DEPRECATED_SECTION_IDS:
|
||||
return "Deprecated"
|
||||
return "Unclassified"
|
||||
|
||||
|
||||
def classify_endpoint(endpoint: str) -> str:
|
||||
normalized = normalize_endpoint(endpoint)
|
||||
if normalized.startswith("/static") or normalized in {"/trader-mode", "/trader-mode.html"}:
|
||||
return "Mainline"
|
||||
if "/build-ticket" in normalized:
|
||||
return "Deprecated"
|
||||
if normalized.startswith(DEPRECATED_ENDPOINT_PREFIXES):
|
||||
return "Deprecated"
|
||||
if normalized.startswith(RESEARCH_ONLY_ENDPOINT_PREFIXES):
|
||||
return "Research Only"
|
||||
if normalized.startswith(MAINLINE_ENDPOINT_PREFIXES):
|
||||
return "Mainline"
|
||||
if normalized.startswith(SYSTEM_OPS_ENDPOINT_PREFIXES):
|
||||
return "System Ops"
|
||||
if normalized == "/trading/watch/run":
|
||||
return "System Ops"
|
||||
return "Unclassified"
|
||||
|
||||
|
||||
def read_text(path: Path) -> str:
|
||||
return path.read_text(encoding="utf-8")
|
||||
|
||||
|
||||
def collect_workspace_sections(index_html: Path = INDEX_HTML) -> list[dict]:
|
||||
text = read_text(index_html)
|
||||
return [
|
||||
{
|
||||
"id": section_id,
|
||||
"label": label,
|
||||
"category": classify_section(section_id),
|
||||
}
|
||||
for section_id, label in SECTION_RE.findall(text)
|
||||
]
|
||||
|
||||
|
||||
def collect_nav_targets(index_html: Path = INDEX_HTML) -> list[dict]:
|
||||
text = read_text(index_html)
|
||||
return [
|
||||
{
|
||||
"id": target,
|
||||
"label": label.strip(),
|
||||
"category": classify_section(target),
|
||||
}
|
||||
for target, label in NAV_RE.findall(text)
|
||||
]
|
||||
|
||||
|
||||
def collect_system_ops_targets(index_html: Path = INDEX_HTML) -> list[dict]:
|
||||
text = read_text(index_html)
|
||||
return [
|
||||
{
|
||||
"id": target,
|
||||
"label": label.strip(),
|
||||
"category": classify_section(target),
|
||||
}
|
||||
for target, label in SYSTEM_OPS_RE.findall(text)
|
||||
]
|
||||
|
||||
|
||||
def collect_api_routes(api_server: Path = API_SERVER) -> list[dict]:
|
||||
text = read_text(api_server)
|
||||
routes = []
|
||||
for method, endpoint in ROUTE_RE.findall(text):
|
||||
normalized = normalize_endpoint(endpoint)
|
||||
routes.append(
|
||||
{
|
||||
"method": method,
|
||||
"endpoint": normalized,
|
||||
"category": classify_endpoint(normalized),
|
||||
"source": "src/api/server.py",
|
||||
}
|
||||
)
|
||||
return sorted(routes, key=lambda item: (item["endpoint"], item["method"]))
|
||||
|
||||
|
||||
def collect_frontend_api_references(paths=None) -> list[dict]:
|
||||
paths = [APP_JS, TRADER_MODE_JS] if paths is None else paths
|
||||
references = {}
|
||||
for path in paths:
|
||||
text = read_text(path)
|
||||
for match in FRONTEND_ENDPOINT_RE.findall(text):
|
||||
raw = next(part for part in match if part)
|
||||
endpoint = normalize_endpoint(raw)
|
||||
references.setdefault(endpoint, set()).add(display_path(path))
|
||||
return [
|
||||
{
|
||||
"endpoint": endpoint,
|
||||
"category": classify_endpoint(endpoint),
|
||||
"sources": sorted(sources),
|
||||
}
|
||||
for endpoint, sources in sorted(references.items())
|
||||
]
|
||||
|
||||
|
||||
def collect_test_endpoint_references(tests_dir: Path = TESTS_DIR) -> list[dict]:
|
||||
references = defaultdict(set)
|
||||
for path in sorted(tests_dir.glob("test_*.py")):
|
||||
text = read_text(path)
|
||||
for raw in TEST_ENDPOINT_RE.findall(text):
|
||||
endpoint = normalize_endpoint(raw)
|
||||
references[endpoint].add(display_path(path))
|
||||
return [
|
||||
{
|
||||
"endpoint": endpoint,
|
||||
"category": classify_endpoint(endpoint),
|
||||
"sources": sorted(sources),
|
||||
}
|
||||
for endpoint, sources in sorted(references.items())
|
||||
]
|
||||
|
||||
|
||||
def build_audit() -> dict:
|
||||
sections = collect_workspace_sections()
|
||||
nav_targets = collect_nav_targets()
|
||||
system_ops_targets = collect_system_ops_targets()
|
||||
api_routes = collect_api_routes()
|
||||
frontend_references = collect_frontend_api_references()
|
||||
test_references = collect_test_endpoint_references()
|
||||
|
||||
endpoint_categories = Counter(item["category"] for item in api_routes)
|
||||
frontend_categories = Counter(item["category"] for item in frontend_references)
|
||||
section_categories = Counter(item["category"] for item in sections)
|
||||
|
||||
return {
|
||||
"policy": {
|
||||
"mainline_chain": (
|
||||
"Range / Draw / Location -> Liquidity / Sweep / Inducement / Path "
|
||||
"-> Displacement / MSS / FVG / Retest / Session -> backtest evidence "
|
||||
"-> pre-market plan -> intraday focus/no-trade -> journal feedback"
|
||||
),
|
||||
"execution_boundary": "read_only_analysis_no_order_submission",
|
||||
"physical_delete_allowed": False,
|
||||
},
|
||||
"nav_targets": nav_targets,
|
||||
"workspace_sections": sections,
|
||||
"system_ops_targets": system_ops_targets,
|
||||
"api_routes": api_routes,
|
||||
"frontend_api_references": frontend_references,
|
||||
"test_endpoint_references": test_references,
|
||||
"summary": {
|
||||
"nav_count": len(nav_targets),
|
||||
"workspace_section_count": len(sections),
|
||||
"system_ops_target_count": len(system_ops_targets),
|
||||
"api_route_count": len(api_routes),
|
||||
"frontend_api_reference_count": len(frontend_references),
|
||||
"test_endpoint_reference_count": len(test_references),
|
||||
"section_categories": dict(sorted(section_categories.items())),
|
||||
"api_route_categories": dict(sorted(endpoint_categories.items())),
|
||||
"frontend_reference_categories": dict(sorted(frontend_categories.items())),
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
def format_markdown(audit: dict) -> str:
|
||||
lines = [
|
||||
"# Trader Mainline Surface Audit",
|
||||
"",
|
||||
f"- Execution boundary: `{audit['policy']['execution_boundary']}`",
|
||||
f"- Physical delete allowed now: `{str(audit['policy']['physical_delete_allowed']).lower()}`",
|
||||
f"- Mainline chain: {audit['policy']['mainline_chain']}",
|
||||
"",
|
||||
"## Navigation",
|
||||
"",
|
||||
"| Target | Label | Category |",
|
||||
"| --- | --- | --- |",
|
||||
]
|
||||
for item in audit["nav_targets"]:
|
||||
lines.append(f"| `{item['id']}` | {item['label']} | {item['category']} |")
|
||||
lines.extend(["", "## Workspace Sections", "", "| Section | Label | Category |", "| --- | --- | --- |"])
|
||||
for item in audit["workspace_sections"]:
|
||||
lines.append(f"| `{item['id']}` | {item['label']} | {item['category']} |")
|
||||
lines.extend(["", "## API Route Category Counts", "", "```json"])
|
||||
lines.append(json.dumps(audit["summary"]["api_route_categories"], ensure_ascii=False, sort_keys=True, indent=2))
|
||||
lines.extend(["```", ""])
|
||||
return "\n".join(lines)
|
||||
|
||||
|
||||
def display_path(path: Path) -> str:
|
||||
try:
|
||||
return str(path.relative_to(ROOT)).replace("\\", "/")
|
||||
except ValueError:
|
||||
return str(path)
|
||||
|
||||
|
||||
def main(argv=None) -> int:
|
||||
parser = argparse.ArgumentParser(description="Audit trader-facing surfaces against the ICT mainline plan.")
|
||||
parser.add_argument("--output-json", action="store_true", help="Print JSON instead of Markdown.")
|
||||
args = parser.parse_args(argv)
|
||||
audit = build_audit()
|
||||
if args.output_json:
|
||||
print(json.dumps(audit, ensure_ascii=False, sort_keys=True, indent=2))
|
||||
else:
|
||||
print(format_markdown(audit))
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
@@ -20,6 +20,7 @@ NONEXISTENT_VISUAL_PLAN_NAME = "AI_ICT_" + "视觉盯盘与主动告警增强方
|
||||
ACTIVE_TOP_LEVEL_DOCS = {
|
||||
"AI_ICT_硬性主线约束_必须遵循ICT交易全书_2026-05-21_v1.md",
|
||||
"AI_ICT_实盘辅助分析决策助手ICT主线开发方案_2026-05-21_v1.md",
|
||||
"AI_ICT_主线裁剪审计_S1_2026-05-21_v1.md",
|
||||
"AI_ICT_主线纠偏与功能裁剪方案_2026-05-20_v1.md",
|
||||
"AI_ICT_实盘辅助分析决策助手上线必做清单_2026-05-18_v1.md",
|
||||
"AI_ICT_实盘辅助分析决策助手使用说明_2026-05-18_v1.md",
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
import unittest
|
||||
|
||||
from scripts import audit_trader_mainline_surfaces as audit
|
||||
|
||||
|
||||
class TraderMainlineSurfaceAuditTests(unittest.TestCase):
|
||||
def test_main_navigation_is_reduced_to_five_trader_entries(self) -> None:
|
||||
nav_targets = audit.collect_nav_targets()
|
||||
self.assertEqual(
|
||||
[item["id"] for item in nav_targets],
|
||||
["trader-mode", "strategy-backtest", "trading-plan", "journal", "system-ops"],
|
||||
)
|
||||
self.assertEqual(
|
||||
[item["category"] for item in nav_targets],
|
||||
["Mainline", "Mainline", "Mainline", "Mainline", "System Ops"],
|
||||
)
|
||||
|
||||
def test_workspace_sections_are_classified_before_deletion(self) -> None:
|
||||
sections = audit.collect_workspace_sections()
|
||||
categories = {item["id"]: item["category"] for item in sections}
|
||||
self.assertEqual(categories["trader-mode"], "Mainline")
|
||||
self.assertEqual(categories["strategy-backtest"], "Mainline")
|
||||
self.assertEqual(categories["trading-plan"], "Mainline")
|
||||
self.assertEqual(categories["journal"], "Mainline")
|
||||
self.assertEqual(categories["system-ops"], "System Ops")
|
||||
self.assertEqual(categories["decision-assistant"], "Research Only")
|
||||
self.assertEqual(categories["visual-reviews"], "Research Only")
|
||||
self.assertEqual(categories["execution-tickets"], "Deprecated")
|
||||
self.assertEqual(categories["position-management"], "Deprecated")
|
||||
self.assertNotIn("Unclassified", categories.values())
|
||||
|
||||
def test_system_ops_links_cover_non_mainline_sections(self) -> None:
|
||||
sections = {item["id"] for item in audit.collect_workspace_sections()}
|
||||
system_ops_targets = audit.collect_system_ops_targets()
|
||||
for item in system_ops_targets:
|
||||
self.assertIn(item["id"], sections)
|
||||
self.assertNotEqual(item["category"], "Mainline")
|
||||
|
||||
def test_endpoint_classification_keeps_execution_surfaces_out_of_mainline(self) -> None:
|
||||
self.assertEqual(audit.classify_endpoint("/trading/backtests"), "Mainline")
|
||||
self.assertEqual(audit.classify_endpoint("/trading/plans/latest"), "Mainline")
|
||||
self.assertEqual(audit.classify_endpoint("/trading/journal"), "Mainline")
|
||||
self.assertEqual(audit.classify_endpoint("/trading/workflow-archive"), "Research Only")
|
||||
self.assertEqual(audit.classify_endpoint("/trading/external-context-surface-history"), "Research Only")
|
||||
self.assertEqual(audit.classify_endpoint("/trading/tickets"), "Deprecated")
|
||||
self.assertEqual(audit.classify_endpoint("/trading/executions"), "Deprecated")
|
||||
self.assertEqual(audit.classify_endpoint("/trading/okx-sandbox-preflight"), "Deprecated")
|
||||
self.assertEqual(audit.classify_endpoint("/trading/candidates/4/build-ticket"), "Deprecated")
|
||||
self.assertEqual(audit.classify_endpoint("/trading/watch/run"), "System Ops")
|
||||
|
||||
def test_frontend_api_references_are_classified(self) -> None:
|
||||
references = audit.collect_frontend_api_references()
|
||||
categories = {item["endpoint"]: item["category"] for item in references}
|
||||
self.assertEqual(categories["/trading/backtests"], "Mainline")
|
||||
self.assertEqual(categories["/trading/workflow-archive"], "Research Only")
|
||||
self.assertEqual(categories["/trading/executions"], "Deprecated")
|
||||
self.assertNotIn("Unclassified", categories.values())
|
||||
|
||||
def test_audit_summary_preserves_read_only_boundary(self) -> None:
|
||||
result = audit.build_audit()
|
||||
self.assertFalse(result["policy"]["physical_delete_allowed"])
|
||||
self.assertEqual(result["policy"]["execution_boundary"], "read_only_analysis_no_order_submission")
|
||||
self.assertEqual(result["summary"]["nav_count"], 5)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user