v3.0 测试体系设计
作者: 庞统(综合) + 司马懿(v30 草案 + 背靠背审查)
日期: 2026-06-05(v3.0 合并版)
状态: 待主公确认
覆盖设计文档: #01 四相循环 / #07 Acquire-First / #08 Classify / #09 Rebuttal / #06 PM2 恢复 / #04 黑板协作 / #10 T3 需求探索 / #12 Pipeline / architecture-v3.0
替代: 本文档替代 docs/test-plan-e2e-v27.md(v2.7 初版,2026-05-18)
〇、设计原则(主公三原则 + 仲达补充)
原则一:精准测试,最小代价覆盖修改内容
- 改了什么模块就跑什么测试,不默认跑全量
- 全量测试由用户手动触发
- 测试文件命名要让人一看就知道改了什么该跑什么
原则二:从设计文档正推覆盖
- 不是"有什么函数测什么",而是"设计定义了哪些行为就测哪些"
- 每个设计文档对应的测试覆盖要显式标注
原则三:真实环境测试 + 测完清理
- E2E 不搞独立 daemon、独立进程、独立数据
- 最终汇聚点是真实 Agent,独立环境测不出真实链路
- 正确做法:真实环境跑测试 → 测完清掉测试数据
原则四:串行场景 + 并行压力分离(主公新增)
- 场景测试:逐个执行,一个跑完收集结果、分析根因、解决后再跑下一个。用时间换可靠性
- 压力测试:单独一轮,多任务并行,验证并发控制、全局上限等
- 两类测试不混在一起
一、问题诊断
1.1 现有测试的致命缺陷
| 缺陷 |
根因 |
后果 |
| E2E 全部写真实 data_root |
TestClient 直连生产 DB,无隔离 |
每次跑 pytest tests/ 残留 e2e-v27 项目,PM2 重启触发广播风暴 |
| E9-E14 cleanup 调不存在的 API |
/projects/{pid}/archive 未实现 |
异常被吞,数据不清理 |
| 无分层 |
单文件 62K,所有测试混在一起 |
改个小 bug 要跑全量 |
| Agent 无意义响应 |
残留 pending 任务被 daemon 广播 |
浪费 token + 干扰正常工作 |
| 无数据清理能力 |
项目删不掉、测试邮件堆积 |
测试和生产数据混杂 |
1.2 Review 发现的额外问题
| 问题 |
说明 |
| E14 编号冲突 |
设计文档 E14="AgentBusyError 分类"(3 个测试),代码 E14="Rollback"(1 个测试),同名不同义 |
| 设计文档严重滞后 |
v31 新增 9 个测试类 + test_four_phase.py ~20 个测试未入文档 |
| E15.2/E15.3 完全缺失 |
Executor prompt / Reviewer prompt 无任何层级测试 |
| E2E gate 不统一 |
E1-E8 无 RUN_INTEGRATION gate,E9-E14 有。现已统一加 gate |
二、分层架构
2.1 三层测试金字塔
关键规则:只有 E2E 层 spawn 真实 Agent。Unit 和 Integration 层不 spawn。
2.2 各层定位
| 维度 |
单元测试 |
集成测试 |
E2E 测试 |
| 目标 |
验证单个函数/类的逻辑正确性 |
验证 API 端点 + DB 交互 |
验证完整链路(真实 Daemon + Agent) |
| 数据 |
mock/fixture |
tmp_path + 独立 SQLite |
真实 data_root + 测试前缀隔离 |
| Agent |
❌ 不 spawn |
❌ 不 spawn |
✅ 真实 spawn |
| 清理 |
N/A(不产生数据) |
tmp_path 自动清理 |
清理 API teardown 删除 |
| 速度 |
<1s/测试 |
1-5s/测试 |
30-300s/测试 |
| 频率 |
每次提交 |
改了 API 层跑 |
部署前(手动触发) |
2.3 改动 → 测试映射(原则一)
改了 X,应该跑哪些测试?
| 改动的模块 |
必跑测试 |
pytest 命令 |
src/blackboard/db.py(数据模型) |
unit/test_models + integration |
pytest tests/unit/test_models.py tests/integration/ |
src/blackboard/db.py(状态机) |
unit/test_state_machine + integration |
pytest -m state_machine |
src/daemon/spawner.py(classify) |
unit/test_classify_outcome |
pytest -m classify |
src/daemon/spawner.py(acquire/release) |
unit/test_spawner + e2e/test_spawner_e2e |
pytest tests/unit/test_spawner.py tests/e2e/test_spawner_e2e.py |
src/daemon/ticker.py(广播) |
unit/test_broadcast_tracker + integration |
pytest -m broadcast |
src/daemon/ticker.py(超时) |
unit/test_timeout + integration |
pytest tests/integration/test_ticker_integration.py -k timeout |
src/daemon/router.py |
unit/test_router |
pytest tests/unit/test_router.py |
src/daemon/counter.py |
unit/test_counter |
pytest tests/unit/test_counter.py |
src/daemon/dispatcher.py |
unit/test_dispatcher + integration |
pytest tests/unit/test_dispatcher.py tests/integration/test_dispatcher_integration.py |
src/api/mail_routes.py |
integration/test_api_mail |
pytest -m mail |
src/api/blackboard_routes.py |
integration/test_api_tasks + reviews |
pytest tests/integration/ -k task |
src/daemon/review.py |
unit/test_rebuttal + integration |
pytest -m review |
快速验证:pytest -m "not e2e"(~2-5 分钟,不含 E2E)
三、E2E 执行策略(原则四展开)
3.1 两大类别
| 类别 |
目标 |
执行方式 |
文件 |
| 场景测试 |
逐个验证每个场景的正确性 |
严格串行:一个 case 跑完 → 收集结果 → 根因分析(如有问题)→ 修 → 再跑下一个 |
test_e2e_scenarios.py |
| 压力测试 |
验证并发控制、全局上限、资源竞争 |
并行:多任务同时 broadcast/dispatch/spawn |
test_e2e_stress.py |
3.2 场景测试流程(串行)
实现方式:
- pytest 默认串行执行(不用 xdist)
- 每个测试函数是独立场景
scope="module" 的 fixture 共享 daemon 连接
- 测试间无共享状态,各自创建/清理数据
3.3 压力测试流程(并行)
3.4 数据清理与诊断分离
3.5 前置依赖:数据清理 API
E2E 测试能安全运行的前提:
| 需求 |
API |
状态 |
| 项目物理删除 |
DELETE /api/projects/{pid}?physical=true |
✅ 已实现(src/api/project_routes.py) |
| 邮件批量删除 |
DELETE /api/mail?prefix=e2e- |
✅ 已实现(src/api/mail_routes.py) |
四、E2E 场景清单
编号规则:S = Scenario(场景测试),ST = Stress(压力测试)
原文档 E1-E15 重新编号,解决 E14 冲突
4.1 场景测试(S1-S15,串行执行)
S1: 项目管理(4 个测试)| 对应 design: architecture-v3.0 §5
- S1.1 创建项目(POST /api/projects)
- S1.2 项目列表(GET /api/projects)
- S1.3 自动发现(含 blackboard.db 的目录自动注册)
- S1.4 归档项目(status=archived,目录不移动)
S2: Task CRUD + 状态机(5 个测试)| 对应 design: architecture-v3.0 §5.2
- S2.1 创建 Task(POST /api/projects/{pid}/tasks)
- S2.2 查询 Task(GET,expand=all)
- S2.3 合法状态转换(pending → claimed → working → review → done)
- S2.4 非法转换拒绝(409 + valid_transitions)
- S2.5 列表筛选(status/assignee/parent_task)
S3: SubTask 父子关系(4 个测试)| 对应 design: architecture-v3.0 §5
- S3.1 创建父 Task + 3 个子 Task
- S3.2 list_subtasks 验证
- S3.3 top_level_tasks 排除子 Task
- S3.4 子 Task 的 stage 字段
S4: Stage 进度(3 个测试)| 对应 design: architecture-v3.0 §5
- S4.1 带 stages_json 的父 Task → 子 Task 分配到各 stage → progress 端点
- S4.2 空 stage 的父 Task 进度
- S4.3 stage 分组统计验证
S5: 父 Task 状态聚合(6 个测试)| 对应 design: architecture-v3.0 §6.1
- S5.1 all done → 父 done
- S5.2 has review → 父 review
- S5.3 has working → 父 working
- S5.4 all pending → 父 pending
- S5.5 cancelled 子 Task 排除
- S5.6 手动状态(cancelled 父 Task)不被覆盖
S6: 依赖链(3 个测试)| 对应 design: architecture-v3.0 §6.1
- S6.1 Task B depends_on Task A,A done 后 B 自动 pending(Ticker 推进)
- S6.2 A 未完成时 B 保持 blocked
- S6.3 多层依赖(A → B → C)
S7: 超时回收(2 个测试)| 对应 design: architecture-v3.0 §6.1
- S7.1 claimed 超时 → pending
- S7.2 working 超时 → failed
S8: Mail(7 个测试)| 对应 design: architecture-v3.0 §12
- S8.1 发送 Mail(inform 类型 → 自动 done)
- S8.2 发送 Mail(task-assign 类型 → pending)
- S8.3 Mail 列表 + 筛选(from/to/unread)
- S8.4 Mail 详情(含 comments)
- S8.5 标记已读
- S8.6 标记已执行
- S8.7 Mail summary + agents 列表
S9: 真实 Agent 调度(3 个测试)| 对应 design: #01 四相循环 + architecture-v3.0 §14
- S9.1 创建简单 Task → Ticker 调度 → Agent spawn → Agent 回写 working → 完成任务(#01)
- S9.2 创建 review 类型 Task → 调度到 simayi-challenger → 回写 review 结果(#01)
- S9.3 Guardrail 拦截(不合法任务 → Agent 拒绝执行)(architecture-v3.0 §14)
Agent 任务内容:简单的"echo hello"级别任务,10-30 秒完成
S10: 全链路集成(2 个测试)| 对应 design: #01 四相循环
- S10.1 逻辑链(创建项目 → 父 Task + 子 Task → Ticker tick → 依赖推进 → 聚合刷新 → Mail 通知 → 验证完整状态链)
- S10.2 Agent 全链(含真实 Agent spawn + 执行 + 产出 + review)
S11: Spawner Acquire-First(6 个测试)| 对应 design: #07
- S11.1 Phase 0 Pre-acquire revive:任务 timeout/failed → Phase 0 自动 revive → Phase 1 acquire 成功
- S11.2 Phase 0 假死检测:status=running + lock PID 死 → Phase 0 自动 revive
- S11.3 Phase 1 Counter acquire 互斥:同 agent 并发 spawn → 第二个 AgentBusyError(reason=counter_blocked)
- S11.4 Phase 2 Session check 锁保护:counter acquire 后 → session check 在锁保护下执行 → session locked → release counter → AgentBusyError(reason=session_locked)
- S11.5 Phase 2 Blockers 收集:多 blocker 并列收集(locked + compact)→ 返回全部 blockers
- S11.6 Phase 3 on_checks_passed 异常回滚:on_checks_passed 抛异常 → counter 自动 release
S12: 超时统一处理(4 个测试)| 对应 design: #08 §3.7
- S12.1 crash_limit 统一检查(working):executor crash 3 次/30min → _check_timeouts 标 failed
- S12.2 crash_limit 统一检查(review):reviewer crash 3 次/30min → _check_timeouts 标 failed
- S12.3 updated_at fallback:mail auto-working 无 started_at/claimed_at → updated_at fallback 生效 → 超时回收
- S12.4 process_dead 对 review 状态:review agent 进程死 → 保持 review 状态 → 等 _dispatch_reviews 处理
S13: Compact Hanging(3 个测试)| 对应 design: #07 §4.5
- S13.1 compact_hanging release counter:compact 等超限 → compact_hanging → release counter → 任务保持 working
- S13.2 compact_hanging 后 ticker 重新 dispatch:compact_hanging → ticker _check_timeouts 检测超时 → 推回 pending → 重新 dispatch
- S13.3 retry 遇 session busy 释放 counter:_do_retry 遇 AgentBusyError → release counter → 任务保持 working → ticker 重新 dispatch
S14: AgentBusyError 分类(3 个测试)| 对应 design: #07 §2
⚠️ 原设计文档 E14="AgentBusyError 分类"与代码中 E14="Rollback" 冲突,此处统一修正
- S14.1 counter_blocked:counter acquire 失败 → AgentBusyError(reason=counter_blocked)
- S14.2 session_locked/running/compacting:Phase 2 各种 blocker → AgentBusyError 携带具体 reason + detail.blockers
- S14.3 Dispatcher 错误区分:dispatcher 捕获 AgentBusyError → 日志记录具体原因 → 路由决策写入 routing_decisions
S15: Crash Rollback(1 个测试)| 对应 design: #07 §4.5
⚠️ 原代码中 E14="Rollback",现独立编号为 S15
- S15.1 crash 后 current_agent 回退验证:Agent crash → current_agent 指针回退 → 任务可被重新 dispatch
S16: 广播认领扩展(2 个测试)| 对应 design: architecture-v3.0 §8.3
- S16.1 不匹配 Agent 写 observation comment(非 NO_REPLY)
- S16.2 匹配 Agent 正常认领
S17: Pause/Resume(1 个测试)| 对应 design: architecture-v3.0 §5.2
- S17.1 paused → resumed_from 状态流转
S18: Cancelled Restart(1 个测试)| 对应 design: architecture-v3.0 §5.2
- S18.1 cancelled → pending 重启
S19: Retry Chain(1 个测试)| 对应 design: #08 §3.3
- S19.1 failed → pending retry 链路
S20: Full Lifecycle with Review(1 个测试)| 对应 design: #09
- S20.1 创建 → 认领 → 执行 → review → rebuttal → done 全链路
注:原代码有 3 个独立测试(html_no_cache, js_immutable, css_immutable),设计中 S21.2 将 JS+CSS 合并为"静态资源 immutable 缓存"一个场景,因为两者验证逻辑一致
- S21.1 HTML 不缓存
- S21.2 JS/CSS immutable 缓存(原 2 个测试合并)
场景测试合计:58 个测试
4.2 压力测试(ST1-ST3)
ST1: 并发 Counter 竞争
- 同时创建 3 个任务指定同一 Agent → 第 2、3 个 AgentBusyError(reason=counter_blocked)
- 第 1 个完成后 counter release → 第 2 个 acquire 成功
- 验证 counter release 后下一个 acquire 成功
ST2: 全局并发上限
- 同时创建 5 个任务指定不同 Agent → 全部 acquire 成功(5/5)
- 第 6 个任务 → 被拒绝或排队
- 验证全局计数器准确
ST3: Broadcast 并发
- 同时广播 3 个任务 → 全部任务在 5min 内到达终态
- 验证无死锁(通过全部终态判定)
- 验证广播计数器正确递增
压力测试合计:3 个测试组
4.3 Prompt 集成测试(P1,延后)
以下场景需要验证 Agent prompt 行为,标 P1 延后
- P1.1 Executor prompt 任务式指挥:executor 不再收到步骤列表,收到意图+终态+约束 → 自主决策步骤
- P1.2 Reviewer prompt 挑战者思维:reviewer 审查时用挑战者视角 + confidence 自评
五、测试文件组织
5.1 目录结构
5.2 现有测试迁移映射
| 现有文件 |
去向 |
处理 |
| test_e2e_v27.py E1-E8 |
integration/ |
重写为 API 集成测试,用 tmp_path 隔离 |
| test_e2e_v27.py E9-E14 |
e2e/test_e2e_scenarios.py |
按 S9-S15 重新编号 |
| test_e2e_v31.py E94-E98 |
e2e/test_e2e_scenarios.py |
按 S16-S21 编号 |
| test_e2e_v31.py E10c/E10d |
e2e/test_e2e_scenarios.py |
按 S19-S20 编号 |
| test_e2e_v31.py E15a/E15b |
e2e/test_e2e_scenarios.py |
按 S16.1-S16.2 编号(Prompt v3 broadcast) |
| test_four_phase.py |
e2e/test_four_phase.py |
加 RUN_INTEGRATION gate |
| test_spawner_e2e.py |
e2e/test_spawner_e2e.py |
已有 gate ✅ |
| test_api.py |
integration/ |
保持 |
| test_api_mail.py |
integration/ |
保持 |
| test_main.py |
integration/ |
保持 |
5.3 pytest marker 定义
5.4 Gate 保护
| 层级 |
Gate |
说明 |
| unit |
无 |
纯 mock,安全 |
| integration |
无 |
tmp_path 隔离,安全 |
| e2e |
RUN_INTEGRATION=1 |
所有 e2e 测试统一 gate,@skip_no_integration |
六、设计文档 → 测试覆盖映射(原则二)
6.1 覆盖矩阵
| 设计文档 |
关键行为 |
单元测试 |
集成测试 |
E2E 测试 |
| architecture-v3.0.md |
状态机、数据模型、API 契约 |
P0 |
P0 |
— |
| #01 四相循环 |
spawn→execute→classify→retry/advance |
P1 |
— |
P0(S9-S10) |
| #07 Acquire-First |
Phase 0-4、AgentBusyError 区分 |
P0 |
P1 |
P1(S11-S15) |
| #08 Classify Outcome |
A0-A14 + B1-B4 场景 |
P0 |
P1 |
P1(S12) |
| #09 Rebuttal |
审查流水线、2 轮反驳 |
P1 |
P0 |
P1(S20) |
| #06 PM2 恢复 |
崩溃后状态恢复、zombie 检测 |
P1 |
— |
P0 |
| #04 黑板协作 |
@mention、comment、产出、review |
P1 |
P0 |
P1 |
| #10 T3 需求探索 |
苏格拉底式对话、需求规格化 |
P1(暂无测试文件) |
— |
— |
| #12 Pipeline |
task_type 路由、状态机约束 |
P2 |
P2 |
— |
6.2 模块 → 测试层级 → 优先级
| 模块 |
单元 |
集成 |
E2E |
对应设计文档 |
| 状态机转换 |
P0 |
P0 |
— |
architecture-v3.0 §5.2 |
| Classify Outcome |
P0 |
P1 |
P1 |
#08 §3 |
| 广播认领 |
P0 |
P1 |
P0 |
architecture-v3.0 §8.3 |
| 邮件系统 |
P1 |
P0 |
P1 |
architecture-v3.0 §12 |
| Acquire-First |
P0 |
P1 |
P1 |
#07 §2 |
| 四相循环 |
P1 |
— |
P0 |
#01 §2 |
| Spawner 进程管理 |
P0 |
P1 |
P1 |
architecture-v3.0 §6.3 |
| Counter 并发控制 |
P0 |
P1 |
— |
architecture-v3.0 §8.2 |
| Router 路由 |
P0 |
P1 |
— |
architecture-v3.0 §8.1 |
| Review/Rebuttal |
P1 |
P0 |
P1 |
#09 §2 |
| Guardrail |
P0 |
P1 |
— |
architecture-v3.0 §14 |
| 数据模型 |
P0 |
P0 |
— |
architecture-v3.0 §5 |
| 依赖推进 |
P0 |
P1 |
— |
architecture-v3.0 §6.1 |
| 超时检测 |
P0 |
P1 |
P1 |
architecture-v3.0 §6.1 |
| @mention / 协作 |
P1 |
P0 |
P1 |
#04 |
| Inbox JSONL |
P0 |
P1 |
— |
architecture-v3.0 §15 |
| SSE 推送 |
P1 |
P0 |
— |
architecture-v3.0 §15 |
| Bootstrap 上下文 |
P1 |
P1 |
— |
architecture-v3.0 §10 |
| PM2 恢复 |
P1 |
— |
P0 |
#06 |
七、E2E 数据隔离与清理
7.1 各层隔离策略
| 层级 |
策略 |
清理方式 |
| 单元 |
mock / 不涉及 IO |
无残留 |
| 集成 |
tmp_path + 独立 SQLite |
fixture teardown 自动清理 |
| E2E |
真实 data_root + e2e- 前缀隔离 |
清理 API + atexit 兜底 |
7.2 E2E 清理机制
7.3 atexit 兜底
八、通过标准
| 类别 |
标准 |
| 场景测试(S1-S21) |
58 个全部通过。失败必须分析根因并修复后才继续 |
| 压力测试(ST1-ST3) |
3 个全部通过。验证并发控制无死锁 |
| P0 必须全部通过 |
S1-S8 + S10 + S11-S14 |
| P1 通过率 ≥ 80% |
S9 + S15-S21 + ST1-ST3(依赖真实 Agent,可能受网络/环境干扰) |
| P1 延后 |
P1.1/P1.2(Prompt 集成,待 Agent prompt 稳定后补) |
| 速度 |
单元 < 30s,集成 < 5min,E2E 场景 < 60min,E2E 压力 < 30min |
| 零残留 |
测试运行前后,GET /projects?search=e2e- 返回 0 条 |
九、实施计划
Phase 0:数据清理 API(前置依赖)
| 任务 |
API |
优先级 |
| 项目物理删除 |
DELETE /api/projects/{pid}?physical=true |
P0 |
| 邮件批量删除 |
DELETE /api/mail?prefix=e2e- |
P0 |
Phase 1:基础设施
| 任务 |
说明 |
| conftest.py 更新 |
marker 注册 + atexit 清理兜底 + tmp_path fixture |
| E2E conftest |
清理 API fixture + session 兜底 + manifest |
| Gate 统一 |
所有 E2E 文件加 @skip_no_integration |
Phase 2:P0 单元测试(已有 394 passed)
| 任务 |
对应设计文档 |
| test_state_machine.py |
architecture-v3.0 §5.2 |
| test_classify_outcome.py |
#08 §3 |
| test_spawner.py(含 Acquire-First) |
#07 §2 |
| test_broadcast_claim.py |
architecture-v3.0 §8.3 |
| test_counter.py |
architecture-v3.0 §8.2 |
| test_guardrails.py(实际在 test_router.py + test_review_integration.py) |
architecture-v3.0 §14 |
Phase 3:集成测试(已有 155 passed)
| 任务 |
说明 |
| test_api_mail.py |
A1-A10 + 批量删除(已到位) |
| test_ticker_integration.py |
广播 + 超时 + 依赖推进 |
| test_spawner_e2e.py |
acquire/release + 监控(E2E 层) |
| test_dispatcher_integration.py |
Router + Guardrail 调度 |
Phase 4:E2E 场景测试(串行)
| 任务 |
覆盖设计文档 |
| S1-S8 API 层场景 |
architecture-v3.0 |
| S9-S10 Agent 调度 |
#01 四相循环 |
| S11-S15 Spawner/Acquire |
#07 + #08 |
| S16-S21 扩展场景 |
各设计文档 |
Phase 5:E2E 压力测试(并行)
| 任务 |
说明 |
| ST1 Counter 竞争 |
同 agent 并发 |
| ST2 全局上限 |
多 agent 并发 |
| ST3 Broadcast 并发 |
多任务广播 |
十、约束和风险
10.1 约束
- 只有 E2E spawn 真实 Agent:Unit 和 Integration 层不 spawn
- E2E 用真实环境:真实 daemon + 真实 Agent,
e2e- 前缀隔离
- 场景测试串行:一个完成再下一个,用时间换可靠性
- 压力测试并行:单独一轮,场景测试全通过后执行
- 测试不依赖执行顺序:每个测试独立创建/清理数据
- 全量 E2E 手动触发:
RUN_INTEGRATION=1 pytest tests/e2e/
- 测试数据前缀规范:所有 E2E 项目名以
e2e- 开头
10.2 风险
| 风险 |
缓解 |
| E2E 场景测试影响生产 Agent |
e2e- 前缀项目,串行执行减少干扰 |
| 清理 API 失败导致残留 |
atexit + session fixture 双保险 |
| E2E 测试不稳定(Agent 响应慢) |
充分 timeout + retry + 失败时保留数据供诊断 |
| 迁移现有测试引入回归 |
先迁移后验证,不删旧文件直到新测试全绿 |
十一、变更记录
| 日期 |
版本 |
变更 |
| 2026-05-18 |
v2.7 |
初版 E1-E10(仲达) |
| 2026-06-01 |
v2.8 |
新增 E11-E15(庞统) |
| 2026-06-05 |
v3.0 |
全面重写:三层分离 + 主公四原则 + 背靠背 review 修正 + E14 编号冲突修复 + 场景/压力分离 + 串行执行策略(庞统综合,基于仲达 v30 草案) |
v3.0 vs v2.8 关键变化
| 维度 |
v2.8 |
v3.0 |
| E2E 执行策略 |
无明确规定 |
串行场景 + 并行压力分离 |
| 编号体系 |
E1-E15(E14 冲突) |
S1-S21 + ST1-ST3(无冲突) |
| Agent spawn |
E1-E8 无 gate |
统一 RUN_INTEGRATION gate |
| 数据隔离 |
未提及 |
真实 data_root + 清理 API + atexit 兜底 |
| 设计覆盖 |
只管 E2E |
全三层 + 设计文档正推映射 |
| 文件组织 |
两大文件 |
按模块拆分 + 命名规范 |