281 lines
16 KiB
Markdown
281 lines
16 KiB
Markdown
# MoFin 开发规范
|
||
|
||
> 版本: v2.1 | 更新: 2026-07-20 | 基于 AgentsMeeting 样板重构 + 冗余事件复盘
|
||
>
|
||
> 📋 样板参考: [AgentsMeeting TEMPLATE-GUIDE.md](../AgentsMeeting/docs/TEMPLATE-GUIDE.md)
|
||
|
||
---
|
||
|
||
## 十条红线
|
||
|
||
1. **先读/写 Spec,再写代码** — 新增功能先写 spec 再实现;修改已有功能先读对应 spec 了解架构和约束再动手。没有 spec 的模块在 Dashboard 不可见,视为未完成
|
||
2. **部署必验** — 部署后不打开 Dashboard F Tab 验证 = 部署未完成
|
||
3. **不可见即不存在** — 组件不在 Dashboard 中显示 = 等于没部署。离线不告警 = 监控缺陷
|
||
4. **实现后同步 Spec** — 每轮开发完毕后,必须将 `specs/{module}.json` 更新为与实际实现一致的状态。文档过期 = 等于没写
|
||
5. **部署目标即验收标准** — 所有代码必须以部署目标环境(Linux 246)为基准编写和测试。禁止使用 Windows 专属 API(`tasklist`、`netstat`、`schtasks`、`wmic`)在 246 部署的代码中
|
||
6. **单一事实源(SSOT)** — 每个文件全系统只有一个权威位置,其他位置只允许硬链接(同 inode),**禁止独立副本**。权威位置:`deploy/profile-scripts/`(cron 脚本)、`/home/hmo/MoFin/`(被 import 的库)、`deploy/bot/`(XMPP bot)。硬链接破坏只会发生在部署动作(scp 替换文件 / git checkout/merge),因此部署链路自带三层自动修复,不需要靠记性:
|
||
- **systemd path watcher**(`profile-scripts-sync.path`):监听 `deploy/profile-scripts/` 目录变化,任何 scp/替换自动触发 `sync_profile_scripts.sh`
|
||
- **git hooks**(`.git/hooks/post-merge` + `post-checkout`):git 操作后自动重链
|
||
- **手动兜底**:`bash deploy/profile-scripts/sync_profile_scripts.sh`(改完文件随手跑)
|
||
- 同步日志:`gateway/logs/link_sync.log`;断链检测同时是 L2 卫生审计的检查项
|
||
- **部署守卫**(`deploy_guard.py`,每 15 分钟全天候):①被跟踪代码文件出现未提交改动 → 自动回滚+重链+告警(git 提交不受影响)②`session-work` 领先 master 且可快进 → 自动 merge+重链+(触及 dashboard 时)重启服务 ③幂等重链 ④cron 引用完整性检查。状态落盘 `gateway/logs/deploy_guard_status.json`,有动作即 XMPP 报备。**禁止直接编辑 246 上任何被跟踪的代码文件**——所有改动必须经 git(详见 `docs/zhiwei-ops-discipline.md`)
|
||
7. **数据路径必须绝对** — 引用数据文件/数据库时,必须写绝对路径并指向权威位置(`/home/hmo/MoFin/data/`)。**禁止**用 `Path(__file__).parent / "data"` 这类相对解析——同一个模块被硬链接到不同位置时会解析出不同的数据库(2026-07-20 三库事件的根因)
|
||
8. **备份/遗留物禁止留在生产数据目录** — `.bak`、`decisions_backup_*`、迁移残留 JSON、废弃 DB,必须在迁移/变更完成时移到 `archive/`。生产数据目录(`MoFin/data` = `web-dashboard/data`)只放活文件。监控脚本扫描生产目录时,遗留物就是未来的假警报
|
||
9. **文件居住宪法(源头防副本)** — 新文件只允许落在三处 canonical:cron 脚本 → `deploy/profile-scripts/`;被 import 的库 → repo 根目录;独立服务 → `deploy/bot/`。**禁止**在 `scripts/` 下新建 cron 脚本副本或库副本(`scripts/` 只放被系统引用的工具)。一次性诊断/修复脚本 → 用完即归档 `archive/YYYYMMDD-*/` 或放 `temp/`。违者由 L2 卫生审计的**自动收尸**处理:`scripts/` 下的影子副本(deploy 同名)和零引用孤儿(mtime>7天)会被自动 `git mv` 到 `archive/YYYYMM-auto/` 并自动提交——不需要人工清理,也不会再堆积(2026-07-22 起,scripts/ 从 186 个文件收尸到个位数)
|
||
10. **死模块必须收尸** — 宣布模块废弃时,必须在同一轮操作中完成收尸六步:①杀进程 ②stop+disable systemd 服务 ③删 cron job ④归档脚本到 `archive/` ⑤归档数据文件 ⑥从期望矩阵/监控中移除。只说"已废弃"不收尸 = 没废弃(小果 bot 以 root 白跑 8 天 2.5GB 的教训)
|
||
10. **监控查"活"不查"在"** — 健康检查必须验证**数据新鲜度**(DB 表 MAX(时间列))而非"文件存在/进程存在"。文件 mtime、进程存活都不构成健康证据——数据 24h 不更新才是事故。禁止拿遗留文件的 mtime 当管道健康指标("数据管道停滞14天"假警报的根因)
|
||
11. **批量 LLM 调用禁止走 hermes gateway agent 通道** — hermes gateway 的 `/v1/chat/completions` **不是透传**,是完整 agent 运行时:每个请求创建带工具(terminal/websearch/patch)的 agent 会话,可能螺旋几十轮、累积 150k+ token,客户端超时后服务端仍空转,重试会叠加新会话形成自我 DDoS(2026-07-21 603288 事件:单次重评螺旋 35 分钟、44 次 terminal 调用)。所有批量/脚本化 LLM 调用必须经 `llm_client.call_llm()`:**OCG 上游直连为主**(裸 completion,key 运行时从 hermes config.yaml 读取,不落盘),gateway 仅作应急兜底。新增 LLM 调用点一律复用 `llm_client`,禁止手写 HTTP 调用
|
||
12. **告警信噪比纪律** — 所有系统 XMPP 告警必须经 `alert_helper.notify()`,禁止直 POST :5805。两级通道:**ACTION**(买入信号/重点推荐/需人工核查)直通不限速、🚨 前缀独立成条,**永不被限速**;**INFO**(部署/卫生/修复/监控报备)同类 30 分钟限 1 条、≤8 行、24h 内容去重(同一问题不重复轰炸)。有意义的信号(重点推荐操作)绝不允许被纯通知淹没;通知型信息零问题 = 零消息(沉默即正常)
|
||
|
||
---
|
||
|
||
## 一、双轨同源规范体系
|
||
|
||
每新增/修改一个独立功能模块,必须先写 `specs/{module}.json`。
|
||
一个来源同时产出两套文档:
|
||
|
||
```
|
||
specs/{module}.json
|
||
├── human_help → ? 按钮(人类看说明/排错)
|
||
└── ai_spec → § 按钮(AI 看接口/约束/依赖)
|
||
```
|
||
|
||
### 什么算一个模块
|
||
|
||
满足以下任一条件即视为独立模块,必须写 spec:
|
||
|
||
- 暴露独立的 HTTP API 端点
|
||
- 在 Dashboard 上有独立 UI 面板(`?` + `§` 按钮)
|
||
- 有独立的配置文件 / 数据文件
|
||
- 可独立部署(如定时任务、数据采集脚本)
|
||
|
||
### Spec 字段标准
|
||
|
||
```json
|
||
{
|
||
"module": "模块名(与 Dashboard 引用名一致)",
|
||
"version": "1.0",
|
||
"purpose": "一句话说明这个模块干什么",
|
||
|
||
"human_help": {
|
||
"title": "面向人类的标题",
|
||
"description": ["说明段落数组"],
|
||
"usage": ["使用步骤数组"],
|
||
"troubleshooting": ["常见问题数组"]
|
||
},
|
||
|
||
"ai_spec": {
|
||
"apis": [
|
||
{"method": "GET", "path": "/api/xxx", "returns": "返回值说明"}
|
||
],
|
||
"dependencies": ["依赖的服务或文件"],
|
||
"constraints": ["AI 必须遵守的约束"],
|
||
"must_not": ["AI 绝对不能做的事"],
|
||
"tests": [{"id": "T1", "name": "测试用例名"}],
|
||
"related_files": ["实现文件路径"]
|
||
}
|
||
}
|
||
```
|
||
|
||
### 当前模块清单
|
||
|
||
| 模块 | spec 路径 | 说明 | 状态 |
|
||
|------|----------|------|------|
|
||
| portfolio | `specs/portfolio.json` | 持仓数据 + 总览 | ✅ |
|
||
| watchlist | `specs/watchlist.json` | 自选股管理 | ✅ |
|
||
| decisions | `specs/decisions.json` | 策略决策库 | ✅ |
|
||
| market | `specs/market.json` | 市场观察数据 | ✅ |
|
||
| signals | `specs/signals.json` | 信号 + 全市场扫描 | ✅ |
|
||
| scanner | `specs/scanner.json` | 全市场选股机制 | ✅ |
|
||
| evaluation | `specs/evaluation.json` | 策略评估 | ✅ |
|
||
| prompts | `specs/prompts.json` | 提示词版本管理 | ✅ |
|
||
| reports | `specs/reports.json` | 分析报告管理 | ✅ |
|
||
| dashboard | `specs/dashboard.json` | Dashboard 自身 | ✅ |
|
||
| health | `specs/health.json` | 健康监控管线 | ✅ |
|
||
| xmpp_monitor | `specs/xmpp_monitor.json` | XMPP 通信可观测性 | ✅ |
|
||
| hygiene | `specs/hygiene.json` | 系统卫生审计(防冗余) | ✅ |
|
||
| price_monitor | `specs/price_monitor.json` | 价格监控 cron | 📋 |
|
||
| strategy_lifecycle | `specs/strategy_lifecycle.json` | 策略生命周期 | 📋 |
|
||
|
||
> 状态: ✅ = spec 已完成 | 📋 = 待编写
|
||
|
||
---
|
||
|
||
## 二、文件位置宪法(2026-07-20 冗余事件后确立)
|
||
|
||
| 内容类型 | 唯一权威位置 | 其他位置的合法形态 |
|
||
|---------|-------------|------------------|
|
||
| cron 脚本(被调度直接执行) | `deploy/profile-scripts/` | profile scripts 目录硬链接(经 `sync_profile_scripts.sh` 同步) |
|
||
| 被 import 的库(mo_*/mofin_*/strategy_*/technical_*) | `/home/hmo/MoFin/`(根目录) | 禁止副本;deploy/profile-scripts 中的同名库文件只能是对 root 的硬链接 |
|
||
| XMPP bot | `deploy/bot/` | `/home/hmo/xmpp_zhiwei_bot.py` 符号链接 |
|
||
| Dashboard 服务 | `web-dashboard/server.py`(= `/home/hmo/MoFin/server.py` 硬链接) | — |
|
||
| 数据文件/数据库 | `/home/hmo/MoFin/data/`(= `web-dashboard/data` 硬链接) | **禁止**任何第二个数据目录 |
|
||
| 归档 | `archive/<主题>-<日期>/` | — |
|
||
| 待销毁 | `trashbox/` | 定期人工清空 |
|
||
|
||
**禁止出现的位置**:`MoFin/scripts/*.py`、`MoFin/` 根目录的 cron 脚本副本、`.hermes/*/scripts/data/`(任何 profile 本地 data 目录存业务数据)、`projects/` 下与生产同名的项目副本。
|
||
|
||
### 死模块收尸清单(红线9 的执行版)
|
||
|
||
```
|
||
宣布模块 X 废弃时,同一轮操作内必须完成:
|
||
□ 杀进程:pkill 或 systemctl stop(确认 ps 无残留)
|
||
□ 服务:systemctl disable + rm unit 文件 + daemon-reload
|
||
□ cron:两个 jobs.json 中删除 X 的 job,确认无残留
|
||
□ 脚本:移到 archive/<模块>-retired-<日期>/
|
||
□ 数据文件:同上
|
||
□ 监控:从期望矩阵/健康检查注册表中移除 X
|
||
□ 记录:CHANGELOG 写明收尸动作
|
||
```
|
||
|
||
---
|
||
|
||
## 三、验证闭环
|
||
|
||
```
|
||
┌────────────┐ ┌──────────┐ ┌──────────┐
|
||
│ G: 规范体系 │────→│ K: 测试 │────→│ F: 健康 │
|
||
│ 定义期望 │ │ 验证实现 │ │ 持续监控 │
|
||
└────────────┘ └──────────┘ └──────────┘
|
||
↑ ↑ │
|
||
└────────────────┼────────────────┘
|
||
│
|
||
┌────────┴────────┐
|
||
│ F 异常 → 触发 K │
|
||
│ K 失败 → 更新 G │
|
||
└─────────────────┘
|
||
```
|
||
|
||
### 核心反馈链路
|
||
|
||
| 方向 | 触发条件 | 动作 |
|
||
|------|---------|------|
|
||
| G → K | 新增/修改 spec | 对应测试 ID 必须新增/更新 |
|
||
| K → F | 测试全部通过 | F Tab 组件标记为已验证 |
|
||
| **F → K** | **F Tab 发现异常** | 触发对应测试重跑,确认是服务故障还是测试过期 |
|
||
| **F → G** | **F Tab 持续异常但测试通过** | 期望矩阵或 spec 过时,应更新 G 和对应 spec |
|
||
|
||
### F — 系统健康度(Dashboard F Tab)
|
||
|
||
- **期望矩阵**:应该运行的服务 vs 实际状态
|
||
- **监控数据**:L0(5min 心跳)/ L1-L2(功能与卫生)作为实时状态输入,详见「四、自检体系责任矩阵」
|
||
- **服务拓扑**:所有服务的健康、端口状态
|
||
- **?§ 覆盖**:F Tab 中的每条服务必须有对应的 ?(human_help)和 §(ai_spec)按钮
|
||
|
||
---
|
||
|
||
## 四、自检体系责任矩阵(L0-L4)
|
||
|
||
> 2026-07-20 确立。原则:**每层职责单一,不重叠不疏漏;判据是"功能是否达成",不是"进程是否活着"**。
|
||
|
||
| 层 | 组件 | 频率 | 职责(唯一) | 判据 |
|
||
|---|------|------|-------------|------|
|
||
| L0 执行心跳 | `agents_health_check.py`(系统 crontab) | 5min | 端口/HTTP/DB 存活 + auto_heal 执行(gateway 重启/key 切换/bot 重启) | 端口通 + HTTP 200 + DB 可写 |
|
||
| L1 功能健康 | `functional_health_check.py`(hermes cron) | 交易时段 15min | 核心模块**功能是否达成**:检查输出物新鲜度/有效性(live_prices/market_snapshots/mtf_cache/macro_context/bot/LLM/cron引擎) | 每模块注册表判据(REGISTRY),输出 `functional_health.json` |
|
||
| L2 系统卫生 | `system_hygiene_audit.py`(hermes cron) | 每日 08:20 | 分叉副本/断裂硬链接/僵尸进程/孤儿文件/死cron/DB新鲜度(红线6-10 enforcement) | 输出 `hygiene_report.json` |
|
||
| L3 修复循环 | `self_repair.py`(hermes cron) | 30min | 读 L1/L2 失败项 → LLM 诊断 → **白名单动作直接修复(报备制)** → `repair_log.jsonl` + XMPP | LLM 只能选白名单动作;每模块每天≤2次防循环 |
|
||
| L4 元监控 | `meta_watchdog.py`(hermes cron) | 每小时 | **自检系统的自检**:L0-L3 输出物新鲜度 + L3 注册状态 + XMPP 桥 | 任何一层死亡直接 XMPP 点名(最后兜底) |
|
||
|
||
**已退休(职责被合并)**:`Cron监护-高频`(cron_watchdog,并入 L3)、`全局cron健康监控-每10分`(cron_health_monitor,并入 L1)。
|
||
|
||
### 报备制(L3 的核心纪律)
|
||
|
||
发现问题 → **直接修复** → 记录日志 → XMPP 报备。不是"发现问题→报告→等指示"。LLM 介入诊断但**只能执行白名单动作**(rerun_script/restart_service/sync_links/switch_llm_key/none),不允许任意代码执行。白名单兜不住的,在 XMPP 里明确说"需要人工"。
|
||
|
||
---
|
||
|
||
## 五、开发流程
|
||
|
||
### 新增功能流程
|
||
|
||
```
|
||
确定模块边界
|
||
│
|
||
├─ 1. 创建 specs/{module}.json
|
||
│ human_help + ai_spec
|
||
│
|
||
├─ 2. 实现功能代码
|
||
│ 包含 /health 端点 + PID 锁(proc_guard)
|
||
│
|
||
├─ 3. 注册到系统
|
||
│ - 端口注册
|
||
│ - 添加到期望矩阵(F Tab 自动检测)
|
||
│
|
||
├─ 4. 编写测试
|
||
│ - ai_spec.tests 添加对应测试标识
|
||
│
|
||
├─ 5. 同步更新 Spec
|
||
│ - 将 specs/{module}.json 更新为与实际实现一致
|
||
│
|
||
└─ 6. 提交 → 部署 → 验证
|
||
```
|
||
|
||
### 修改已有功能流程
|
||
|
||
```
|
||
识别要修改的模块(查看模块清单确定 module 名)
|
||
│
|
||
├─ 1. 读 specs/{module}.json
|
||
│ 重点读 ai_spec:apis / constraints / dependencies / must_not
|
||
│
|
||
├─ 2. 确认理解
|
||
│ - 如果 spec 描述与代码实际行为不一致,优先怀疑 spec 过期
|
||
│
|
||
├─ 3. 修改功能代码
|
||
│ 只改动需求直接涉及的部分,不顺手优化无关代码
|
||
│
|
||
├─ 4. 同步更新 Spec
|
||
│
|
||
└─ 5. 提交 → 部署 → 验证
|
||
```
|
||
|
||
### Git 操作规范
|
||
|
||
| # | 规则 | 说明 |
|
||
|---|------|------|
|
||
| 1 | 开工前必 pull | `git pull --rebase` |
|
||
| 2 | 改完即 commit | 一个逻辑单元一次提交。禁止含密钥 |
|
||
| 3 | 推前必拉 + 配代理 | push 前 `git pull --rebase`。远程操作前配 `:15000` 代理 |
|
||
| 4 | trunk-based | 日常在 main。仅长周期大改开分支 |
|
||
|
||
### 已有编码规范
|
||
|
||
MoFin 已有的编码规范见 `docs/DEVELOPMENT_STANDARDS.md`,包含:
|
||
- 代码结构(mo_models → mo_data → mofin_db 三层)
|
||
- 数据规范(币种、汇率、数据源)
|
||
- DB 规范(表设计、迁移)
|
||
- LLM Prompt 规范
|
||
- Cron 规范(独立运行、幂等性)
|
||
- 测试要求(`run_all_tests.py`)
|
||
|
||
以上规范与本文件互补,不冲突。本文件侧重"先 spec 后代码"和"通过 Dashboard 保证可见性"。
|
||
|
||
---
|
||
|
||
## 六、部署环境
|
||
|
||
| 项目 | 值 |
|
||
|------|-----|
|
||
| **生产环境** | Linux 192.168.1.246 |
|
||
| **代码目录** | `/home/hmo/MoFin/` |
|
||
| **数据库** | `/home/hmo/web-dashboard/data/mofin.db`(SQLite) |
|
||
| **Flask API** | `server.py` → `:8899`(含 Dashboard) |
|
||
| **Python** | 系统 Python 3 |
|
||
|
||
---
|
||
|
||
## 七、文档索引
|
||
|
||
| 文档 | 用途 |
|
||
|------|------|
|
||
| `docs/dev-spec.md` | 本文件 — 开发规范(含十条红线) |
|
||
| `docs/DEVELOPMENT_STANDARDS.md` | 编码规范(已有) |
|
||
| `SYSTEM_ARCHITECTURE.md` | 系统架构(已有) |
|
||
| `docs/cron-catalog.md` | Cron 任务清单(已有) |
|
||
| `docs/DEPLOY.md` | 部署指南 |
|
||
| `docs/QUICKSTART.md` | 快速操作 |
|
||
| `docs/DASHBOARD.md` | Dashboard API 参考 |
|
||
| `docs/HEALTH-PIPELINE.md` | 健康管线文档 |
|
||
| `docs/learned.md` | 经验教训记录 |
|
||
| `docs/decisions/` | 架构决策日志 |
|