refactor: restore architecture governance gates

This commit is contained in:
jxxghp
2026-08-23 20:17:28 +08:00
parent 1d2984b95f
commit 9f3be0ea4b
13 changed files with 1146 additions and 565 deletions
@@ -25,7 +25,7 @@
3. `PluginManager` 的加载、生命周期、注册表、投影、存储、目录、路径、同步、依赖、克隆和文件监控分别由 `app/runtime/extensions/plugin/` 下的单职责组件承担;旧管理器只保留 V3 ABI 门面和兼容调用顺序。
4. 动态插件 API 使用专用 raw 路由;主程序统一响应信封不进入插件 `get_api()`。前端 `pluginApi` 对非 `Response` envelope 的 payload 原样交付调用方。
5. 旧插件导入仅由 `app/runtime/compat/manifest.py` 精确映射;canonical 模块不复制旧 Manager/Helper/Oper 导出。`app/plugins/` 仍是运行时副本,继续排除在宿主架构扫描之外。
6. 当前机器基线为 746 个宿主 Python 模块、6,024 条内部导入边;数据库边界、Adapter→DB、Runtime→DB、Application→DB 及新增 API/Agent/Chain 目标边均为 0。架构门禁、插件兼容快照和基线脚本均已重新生成。
6. 2026-08-23 当前机器基线为 800 个宿主 Python 模块、6,479 条内部导入边;数据库边界、Adapter→DB、Runtime→DB、Application→DB 及新增 API/Agent/Chain 目标边均为 0。架构门禁、插件兼容快照和基线脚本均已重新生成。
7. 订阅写入统一归入 `app/application/subscription/write.py`;插件动态路由和文件夹操作统一归入 `app/application/plugin/routes.py``folders.py`。重构期间新增且未形成插件 ABI 的 `app/application/subscribe.py``app/application/plugins.py` 已直接删除,不进入 compat manifest。
## 2. 范围与明确排除项
@@ -45,7 +45,7 @@
### 2.2 排除项
- **不审计、不迁移 `app/plugins/` 中的代码。**该目录是已安装插件副本,不是后端架构源代码,也不能作为插件兼容性的唯一事实来源。
- 插件兼容基线应读取同工作区独立仓库 `../MoviePilot-Plugins``plugins.v2/``plugins.v3/`,再配合宿主的 SDK、兼容清单和插件管理器契约判断。
- 插件兼容基线应读取同工作区独立仓库 `../MoviePilot-Plugins``plugins.v3/``plugins.v2/` 和 V3 实际会从默认索引回退加载的 `plugins/` 实现,再配合宿主的 SDK、兼容清单和插件管理器契约判断。
- 不把 `app/modules/themoviedb/` 内部第三方或移植代码的局部循环,直接等同于 MoviePilot 自有架构失败。它需要被隔离,但不应优先重写上游库。
- 本轮不主张数据库表结构变更。纯架构批次不得夹带 Alembic 迁移、字段重命名或数据回填。
- 本轮不主张删除 V3 兼容映射。任何删除都应作为显式破坏性变更另行决策。
@@ -99,7 +99,7 @@ MoviePilot V3 已经完成一轮重要基础工作:原 `app/core`、`app/helpe
### 4.3 模块规模
排除 `app/plugins/` 后,当前静态扫描得到 746 个 Python 模块、6,024 条内部导入边。主要一级目录规模如下(代码行数包含注释和空行,用于趋势比较而非质量评分):
排除 `app/plugins/` 后,2026-08-23 当前静态扫描得到 800 个 Python 模块、6,479 条内部导入边。下表保留 2026-08-18 收口时的一级目录规模快照(代码行数包含注释和空行,用于趋势比较而非质量评分):
| 一级目录 | 约代码行数 | Python 文件数 | 判断 |
| --- | ---: | ---: | --- |
@@ -147,8 +147,8 @@ MoviePilot V3 已经完成一轮重要基础工作:原 `app/core`、`app/helpe
| 指标 | 初始审计 | 当前基线 | 说明 |
| --- | ---: | ---: | --- |
| Python 模块数 | 约 654 | 746 | 增量来自单一职责的 Application、Runtime、Adapter、插件组件和维护用例模块 |
| 内部导入边 | 约 5,623 | 6,024 | 显式端口增加模块数但移除了反向边;边数不作为单独质量目标 |
| Python 模块数 | 约 654 | 800 | 增量来自单一职责的 Application、Runtime、Adapter、插件组件和维护用例模块 |
| 内部导入边 | 约 5,623 | 6,479 | 显式端口增加模块数但移除了反向边;边数不作为单独质量目标 |
| SCC 数 | 14 | 1 | 自有代码 SCC 已归零,仅保留 TMDB 移植包内部隔离例外 |
| `adapters -> db` | 存在 | 0 | `PluginHelper``MoviePilotServerHelper` 的本地数据读取已移到组合根/Application |
| `runtime -> db` | 存在 | 0 | 插件存储、服务配置均改为启动注入 |
@@ -159,7 +159,7 @@ Doctor/Monitor 改为惰性公开门面;QQBot、Telegram、TriMedia、UGreen
- `tests/fixtures/architecture/dependency-baseline.json`:模块、边、SCC 和目标边。
- `tests/fixtures/architecture/runtime-contract-baseline.json`SDK、兼容清单、事件和 `run_module` 合同。
- `tests/fixtures/architecture/official-plugin-baseline.json`:独立官方插件仓 V2/V3 导入及钩子快照。
- `tests/fixtures/architecture/official-plugin-baseline.json`:独立官方插件仓 V3 实际可加载的 V3/V2/default 实现导入及钩子快照。
- `app/schemas/exports.py`:Schema 根入口的生成式兼容导出清单。
## 5. 目标架构与依赖方向
@@ -788,9 +788,9 @@ app/agent/execution/ # 执行、流事件、用量、恢复
`app/runtime/compat/manifest.py` 当前约包含:
- 112 个模块别名。
- 113 个模块别名。
- 1 个包别名。
- 8 个模块、约 41 个符号别名。
- 10 个模块、55 个符号别名。
- 3 个虚拟包。
独立插件仓中仍高频使用:
@@ -828,8 +828,8 @@ app/agent/execution/ # 执行、流事件、用量、恢复
- SDK 公开面有机器可读清单和变更审查。
- 每次迁移明确列出旧路径、新路径、身份要求和保留期限。
- 独立插件仓 v2/v3 静态导入扫描通过。
- V3 治理批次不删除现有 112/41 兼容项
- 独立插件仓中 V3 实际可加载实现的静态导入扫描通过。
- V3 治理批次不删除现有 113 个模块别名、1 个包别名和 55 个符号别名
### 6.15 配置、缓存和错误策略分散
@@ -1071,7 +1071,7 @@ startup 注入具体依赖
| 阶段 | 已落地入口 | 已锁定的关键语义 |
| --- | --- | --- |
| 0 | `scripts/architecture/baseline.py``scripts/schema/exports.py`三份 architecture fixture | 模块/边/SCC、SDK/compat、事件、`run_module`、官方插件 V2/V3 导入和钩子快照 |
| 0 | `scripts/architecture/baseline.py``scripts/schema/exports.py`、architecture fixtures | 模块/边/SCC、显式 `__all__` SDK/compat、事件、`run_module`、官方插件 V3/V2/default 有效实现的导入和钩子快照 |
| 0 | `app/adapters/web/plugin/routes.py``app/application/plugin/routes.py` | 主程序继续统一 envelope;动态插件 API 默认 raw,自定义状态码、原生 Response、文件/流响应不被改写 |
| 0 | `MoviePilot-Frontend/src/api/client.ts` | 联邦插件公共客户端遇到非 `Response` payload 时原样返回;合法 envelope 仍保留统一错误反馈 |
| 1 | `app/schemas/exports.py``app/schemas/__init__.py` | Schema 根入口惰性兼容导出,宿主内部使用精确子模块,公开符号由生成清单锁定 |
@@ -6,20 +6,30 @@
> 审计范围:宿主后端;排除 `app/plugins/**` 运行时插件副本
> 规范优先级:`AGENTS.md` 与 `docs/rules/` 高于本文
> 相关文档:`docs/architecture-overview.md`、`docs/refactor/backend-architecture-governance.md`、`docs/refactor/backend-module-refactor-compatibility.md`
> 实施进度:阶段 0~6 的宿主架构能力已完成收口;API/Application 公共复杂度基线已清零,启动组合根的 SystemConfigOper 构造点已由 14 降至 1;API 进程内后台任务已完成首批统一登记,插件仓适配、Outbox 外围扩展和 Model 查询兼容面仍按风险切片推进。
> 实施进度:阶段 0~6 的宿主架构能力已完成收口;API/Application 公共复杂度基线已清零,启动组合根的 SystemConfigOper 构造点已由 14 降至 1;API 进程内后台任务已完成首批统一登记,插件仓适配、Outbox 外围扩展和 Model 查询兼容面仍按风险切片推进。2026-08-23 的长期整改阶段 0 已恢复宿主、启动性能、官方插件和 SDK 契约门禁的可信基线。
## 当前复核结论(2026-08-23
本节是本轮全面复核后的当前事实源。本文后续的阶段实施记录保留历史审计证据,
其中的数量和判断以当时审计提交为准,不能直接当作当前未完成项。
### 长期整改阶段 0:治理门禁恢复(2026-08-23
- 宿主依赖基线已审查 TaskRegistry 接入后的语义差异:当前为 `800` 个模块、`6479` 条内部导入边,12 组重点禁止边继续全部为 `0`,唯一非平凡 SCC 仍是隔离的 TMDB 移植包。
- 启动性能探针会在隔离生命周期中真实创建并释放 TaskRegistrynormal/safe 组件数分别为 `16`/`8`,CI 只读检查使用稳定的宿主模块集合和生命周期组件顺序,不再把 Python/平台模块数量当作硬合同。
- 官方插件快照覆盖 `plugins.v3``plugins.v2` 以及 V3 实际会从 `package.json` 回退加载的 31 个默认实现;`app/plugins/**` 仍只是宿主运行副本,不进入扫描。
- SDK 快照以各模块显式 `__all__` 为公开合同,能够记录赋值别名;`typing``__future__` 等实现期导入不再被误冻结,既有数据库备份门面已补精确导出清单。
- async 阻塞实际债务已由 fixture 中的 10 项下降到 1 项并固化低水位;剩余项是 Scheduler Agent task 查询,后续阶段迁入异步查询边界后归零。
本阶段只修复治理信号和事实源,不把基线刷新当作业务重构完成。后台任务所有权、Module Contract V2、typed runtime、durable 副作用和质量规模化仍按下列 P1/P2 顺序推进。
### 总体判断
当前架构总体合理,已经从跨层混合的遗留单体收敛为**边界清晰的模块化单体**:
- 继续采用单进程控制面是正确选择,不建议现在拆成微服务;插件、调度器、工作流、事件和数据库共享进程内状态,拆分会放大部署、事务和兼容成本。
- `foundation/domain/runtime/adapters/application/chain/api/startup` 的职责方向基本成立;宿主架构基线、复杂度 ratchet、异步阻塞 ratchet 当前均通过。
- 依赖图当前 `796` 个 Python 模块、`6432` 条内部导入边;唯一非平凡 SCC 位于隔离的 TMDB 第三方移植包内部,不应为了指标归零重写。
- 依赖图当前 `800` 个 Python 模块、`6479` 条内部导入边;唯一非平凡 SCC 位于隔离的 TMDB 第三方移植包内部,不应为了指标归零重写。
- 当前主要风险已经从“目录和依赖失控”转移到运行时协议、后台副作用的可靠性和遗留兼容面。换言之,下一阶段重点应是**语义收口和可验证性**,而不是继续搬文件或机械拆大文件。
综合评价:架构方向可持续,生产可用性较高;可演进性仍处于中等水平。现阶段没有静态审计发现必须立即推倒重来的 P0 架构问题,但存在需要按 P1/P2 计划治理的真实债务。
@@ -33,7 +43,7 @@
### P2:中长期可演进性债务
- **大型职责域仍偏重。** 代表性热点包括 `app/chain/subscribe.py`(约 `4141` 行)、`app/chain/transfer.py`(约 `2944` 行)、`app/agent/orchestrator.py`(约 `3535` 行)、`app/agent/llm/provider.py`(约 `3529` 行)、`app/adapters/external/market.py`(约 `2805` 行)和 `app/api/endpoints/agent.py`(约 `2326` 行)。复杂度 ratchet 只保证不超过当前基线,不代表这些文件已经易维护。只有在行为快照、调用命中和事务边界明确后,才值得按用例拆分。
- **大型职责域仍偏重。** 代表性热点包括 `app/chain/subscribe.py`(约 `4141` 行)、`app/chain/transfer.py`(约 `2944` 行)、`app/agent/orchestrator.py`(约 `3540` 行)、`app/agent/llm/provider.py`(约 `3529` 行)、`app/adapters/external/market.py`(约 `3139` 行)和 `app/api/endpoints/agent.py`(约 `2489` 行)。复杂度 ratchet 只保证不超过当前基线,不代表这些文件已经易维护。只有在行为快照、调用命中和事务边界明确后,才值得按用例拆分。
- **类型门禁覆盖面不足。** `mypy.ini` strict 文件清单目前约 `37` 个文件,Agent、Chain、Module、Adapter 大量代码仍依赖动态类型。应从模块契约、生命周期、Repository/Port 和关键 Chain 返回值开始扩展,而不是直接开启全仓 strict。
- **Pylint 仍是增量硬门禁。** `.github/workflows/pylint.yml` 对改动 Python 文件执行硬检查,但全仓报告使用 `|| true` 仅作 advisory。该策略适合存量迁移,却没有形成全仓质量趋势约束;应增加按目录和新增问题数的 ratchet。
- **测试风格存在历史混用。** 当前约 `499` 个测试文件,仍有约 `70``unittest.TestCase` 文件。它不是生产架构缺陷,但会增加 fixture、状态隔离和异步测试迁移成本,应在触碰相关模块时渐进迁移。
@@ -45,7 +55,7 @@
- 全功能多 worker 的误导性配置已由 `app/runtime/topology.py``app/main.py` 拒绝;V3 默认单 worker 的部署事实已经明确。
- 写事务已由组合根/UoW/Outbox 方向收口,`db_update/async_db_update` 为零;不要重新引入 Model 自动提交。
- 已具备 correlation ID、`/health/live``/health/ready`、模块/事件/调度观测端口和兼容 Facade 命中指标;历史文档中“完全缺少观测能力”的描述已过时。
- 旧导入路径、SDK 导出、插件 manifest 和 V1/V2/V3 索引均有白名单或版本约束;兼容层应继续保持“薄、可观测、只增不删”,不应为了清理目录直接删除。
- 旧导入路径、显式 `__all__` SDK 合同、插件 manifest 和 V3 实际可加载的三层索引实现均有白名单或版本约束;兼容层应继续保持“薄、可观测、只增不删”,不应为了清理目录直接删除。
- TMDB 移植包内部 SCC 属于第三方隔离代码,按现状豁免是合理的技术决策。
### 刻意保留的兼容成本