User insight: hardlink breakage only happens at deploy time (scp file replacement / git checkout-merge), so detection must be welded INTO the deploy pipeline, not left to daily audit. Three automatic layers, no reliance on discipline: 1. systemd path watcher (profile-scripts-sync.path): watches deploy/profile-scripts/ directory, auto-fires sync_profile_scripts.sh on any change. Verified: fires within 4s of file replacement, logs to gateway/logs/link_sync.log (runs as hmo user) 2. git hooks (.git/hooks/post-merge + post-checkout on 246 repo): auto re-link after git operations 3. Manual fallback: sync_profile_scripts.sh (now self-logging) dev-spec red line #6 updated: SSOT rule now documents the three layers and states breakage only happens at deploy time.
14 KiB
14 KiB
MoFin 开发规范
版本: v2.0 | 更新: 2026-07-20 | 基于 AgentsMeeting 样板重构 + 冗余事件复盘
📋 样板参考: AgentsMeeting TEMPLATE-GUIDE.md
十条红线
- 先读/写 Spec,再写代码 — 新增功能先写 spec 再实现;修改已有功能先读对应 spec 了解架构和约束再动手。没有 spec 的模块在 Dashboard 不可见,视为未完成
- 部署必验 — 部署后不打开 Dashboard F Tab 验证 = 部署未完成
- 不可见即不存在 — 组件不在 Dashboard 中显示 = 等于没部署。离线不告警 = 监控缺陷
- 实现后同步 Spec — 每轮开发完毕后,必须将
specs/{module}.json更新为与实际实现一致的状态。文档过期 = 等于没写 - 部署目标即验收标准 — 所有代码必须以部署目标环境(Linux 246)为基准编写和测试。禁止使用 Windows 专属 API(
tasklist、netstat、schtasks、wmic)在 246 部署的代码中 - 单一事实源(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 卫生审计的检查项
- systemd path watcher(
- 数据路径必须绝对 — 引用数据文件/数据库时,必须写绝对路径并指向权威位置(
/home/hmo/MoFin/data/)。禁止用Path(__file__).parent / "data"这类相对解析——同一个模块被硬链接到不同位置时会解析出不同的数据库(2026-07-20 三库事件的根因) - 备份/遗留物禁止留在生产数据目录 —
.bak、decisions_backup_*、迁移残留 JSON、废弃 DB,必须在迁移/变更完成时移到archive/。生产数据目录(MoFin/data=web-dashboard/data)只放活文件。监控脚本扫描生产目录时,遗留物就是未来的假警报 - 死模块必须收尸 — 宣布模块废弃时,必须在同一轮操作中完成收尸六步:①杀进程 ②stop+disable systemd 服务 ③删 cron job ④归档脚本到
archive/⑤归档数据文件 ⑥从期望矩阵/监控中移除。只说"已废弃"不收尸 = 没废弃(小果 bot 以 root 白跑 8 天 2.5GB 的教训) - 监控查"活"不查"在" — 健康检查必须验证数据新鲜度(DB 表 MAX(时间列))而非"文件存在/进程存在"。文件 mtime、进程存活都不构成健康证据——数据 24h 不更新才是事故。禁止拿遗留文件的 mtime 当管道健康指标("数据管道停滞14天"假警报的根因)
一、双轨同源规范体系
每新增/修改一个独立功能模块,必须先写 specs/{module}.json。
一个来源同时产出两套文档:
specs/{module}.json
├── human_help → ? 按钮(人类看说明/排错)
└── ai_spec → § 按钮(AI 看接口/约束/依赖)
什么算一个模块
满足以下任一条件即视为独立模块,必须写 spec:
- 暴露独立的 HTTP API 端点
- 在 Dashboard 上有独立 UI 面板(
?+§按钮) - 有独立的配置文件 / 数据文件
- 可独立部署(如定时任务、数据采集脚本)
Spec 字段标准
{
"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 实际状态
- 监控数据:Tier1(5min)/ Tier2(日报)作为实时状态输入
- 服务拓扑:所有服务的健康、端口状态
- ?§ 覆盖: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/ |
架构决策日志 |