diff --git a/docs/architecture-overview.md b/docs/architecture-overview.md index 8160fd8d6..cdf48156c 100644 --- a/docs/architecture-overview.md +++ b/docs/architecture-overview.md @@ -400,8 +400,8 @@ collector 只接受 canonical `eventmanager`、`EventManager()` 及其有限别 `register`/`add_event_listener`;当前宿主有 16 个静态注册点,另保留 1 个由工作流配置驱动的 真实动态注册。`app/plugins/**` 插件副本不进入宿主事实。 -生产者与消费者共用 `scripts/architecture/event_facts.py` 这一份逐调用事实源。当前宿主有 93 个 -生产调用,其中 92 个静态解析为 94 个事件引用,只有 `Command.send_plugin_event` 的插件事件类型 +生产者与消费者共用 `scripts/architecture/event_facts.py` 这一份逐调用事实源。当前宿主有 90 个 +生产调用,其中 89 个静态解析为 91 个事件引用,只有 `Command.send_plugin_event` 的插件事件类型 保持动态;17 个消费注册中 16 个静态、1 个动态。生成的 `runtime-contract-baseline.json` 保存 line-free 事实、数量和枚举索引;人工维护的 `runtime-contract-policy.json` 只批准 consumer 的精确 fingerprint、owner 和理由,任何新增、替换、 @@ -740,7 +740,7 @@ flowchart LR stream/vendor/diagnostic/control-plane 事实是精确 containment。每条初始边的指纹由测试独立冻结, bindings/uses 变化、分类互换、通配导入和初始边增长都会失败;债务删除时同步删除冻结项以禁止恢复, `--write-host` 不会改写人工 policy 或冻结上界。 -- `event_facts` 是生产者/消费者唯一收集源;运行快照记录 93 个生产调用和 17 个消费注册, +- `event_facts` 是生产者/消费者唯一收集源;运行快照记录 90 个生产调用和 17 个消费注册, consumer 的 17 个唯一 fingerprint 另由只读人工 policy 精确准入。CI 将语义 policy 与生成快照 分成独立步骤,前者不能通过刷新后者绕过。 - 任何所有权迁移必须同步更新:canonical 导入、`app/runtime/compat/manifest.py`、 @@ -755,13 +755,13 @@ flowchart LR | 指标 | 当前值 | |---|---:| | Python 模块 | 973 | -| 内部导入边 | 8,357 | +| 内部导入边 | 8,416 | | 非平凡 SCC | 1(精确 containment 的 TMDB 移植包环) | | Application / Chain 具体 Adapter 直连 | 0 / 0 | | Direct egress | 53(债务已清零,53 条精确 containment) | | Module Contract V2 spec | 217(其中 215 个进入 `run_module` 观察面) | | Event Contract | 53 | -| Event producer / consumer | 93(92 静态、1 动态)/ 17(16 静态、1 动态) | +| Event producer / consumer | 90(89 静态、1 动态)/ 17(16 静态、1 动态) | | Model/Oper 自动事务与自建 Session | 0 | | 组合根外 `SystemConfigOper()` | 0 | diff --git a/docs/architecture/optimization-checklist.md b/docs/architecture/optimization-checklist.md index 02d4d0bb2..28317df9d 100644 --- a/docs/architecture/optimization-checklist.md +++ b/docs/architecture/optimization-checklist.md @@ -15,15 +15,15 @@ | ID | 状态 | 问题 | 收口要求 | |---|---|---|---| -| RES-001 | `ACTIVE`(R0) | System API 仍混有日志、Wiki、配置、事件和更新编排 | Application service/Port 拥有业务与 I/O 决策,endpoint 只做传输适配;canonical 旧实现删除 | -| RES-002 | `PLANNED`(R2) | 复杂度门禁漏扫私有方法、类/文件和 Scheduler;原生并发清单不完整 | 事实扫描覆盖全部宿主调用点(排除 `app/plugins/**`),每项有 owner/精确豁免且零增长 | -| RES-003 | `PLANNED`(R3) | Outbox after_commit 失败只有内存 pending 标记,重启不可恢复 | 持久 intent、唯一 handler、claim/fencing、重启回放、幂等和失败观测完整闭环 | -| RES-004 | `PLANNED`(R4) | Startup initializer 与插件市场存在多套 Transport/Adapter/Manager 构造 | 所有构造回收到 composition root,插件兼容只经 SDK/Compat,canonical 不保留重复正式入口 | -| RES-005 | `PLANNED`(R5) | 审计声明、机器门禁、CI 与远端交付状态需要重新校准 | 文档与事实源一致;专项、锁定全量、Pylint、架构/兼容门禁和 GitHub CI 闭环,远端 `0/0` | -R2 已落地门禁基础:`complexity.py --v2` 覆盖私有/嵌套方法、类、文件和 -`app/scheduler/`;`concurrency.py` 覆盖宿主原生并发原语并冻结调用点与词法 owner。 -当前基线只允许删除或收缩,新增调用点和 owner 漂移均阻断 CI;现有历史热点仍须在后续 -叶子中按真实所有权逐项收口,不得以生成基线伪装为债务清零。 +| RES-001 | `DELIVERED`(R1) | System API 仍混有日志、Wiki、配置、事件和更新编排 | `d50177f45`:Application service/Port 拥有业务与 I/O 决策,endpoint 只做传输适配;旧 helper 已删除 | +| RES-002 | `DELIVERED`(R2) | 复杂度门禁漏扫私有方法、类/文件和 Scheduler;原生并发清单不完整 | `f7ca7e517`、`5cd5780d3`:完整宿主 AST、canonical owner/count、低水位与零增长门禁已落地 | +| RES-003 | `DELIVERED`(R3) | Outbox after_commit 失败只有内存 pending 标记,重启不可恢复 | `9d06f91bb`:持久 intent、唯一 handler、claim/fencing、重启回放、幂等和失败观测完整闭环 | +| RES-004 | `DELIVERED`(R4) | Startup initializer 与插件市场存在多套 Transport/Adapter/Manager 构造 | `7f5b8b469` 至 `046b0b305`:构造回收到 composition,兼容门面消费同一 owner,canonical 无重复正式实现 | +| RES-005 | `ACTIVE`(R5) | 审计声明、机器门禁、CI 与远端交付状态需要重新校准 | 文档与事实源一致;专项、锁定全量、Pylint、架构/兼容门禁和 GitHub CI 闭环,远端 `0/0` | +R2 门禁现已完整覆盖私有、dunder、任意控制流嵌套方法、类、文件与 +`app/scheduler/`;`concurrency.py` 扫描完整宿主源码,按 canonical import/alias、 +TaskGroup、可证明的 loop/executor 来源和词法 owner 聚合数量。新增 owner、数量增长以及 +事实下降后未刷新低水位都会阻断 CI;行号移动和普通同名方法不会制造噪音。 ## 1. 结论摘要 @@ -90,7 +90,7 @@ ARCH-204 均达到实现、验证、提交、推送和远端门禁闭环;S4/AR | 指标 | 当前值 | 解释 | |---|---:|---| -| 宿主 Python 模块 / 内部依赖边 | 974 / 8,357 | `dependency-baseline.json` 当前快照 | +| 宿主 Python 模块 / 内部依赖边 | 981 / 8,416 | `dependency-baseline.json` 当前快照 | | 非平凡 SCC | 1 | 仅保留精确 containment 的 29 模块 TMDB 移植包环 | | 跨层 DB 边界债务 | 0 | Application、Chain、API、Agent、Runtime、Workflow 到 DB 的受控债务均为零 | | Model/Oper 事务债务 | 0 | 自建 Session、自动事务装饰器、直接 commit/rollback 等基线均为零 | @@ -98,7 +98,7 @@ ARCH-204 均达到实现、验证、提交、推送和远端门禁闭环;S4/AR | Event Contract | 53 | 均已有 payload model,但当前全部是 diagnostic enforcement | | Python 源码量 | 305,884 行 | 排除 `app/plugins/**`;61 个文件超过 1,000 行,11 个超过 2,000 行 | | 长方法 | 290 个超过 80 行 | AST 统计排除 `app/plugins/**`;65 个超过 150 行,21 个超过 250 行 | -| 全量 mypy 历史债务 | 9,995 / 592 文件 | canonical `SearchChain` Facade 已补齐显式类型转发;strict frontier 当前覆盖 41 个文件,低水位只允许继续下降 | +| 全量 mypy 历史债务 | 9,987 / 592 文件 | canonical `SearchChain` Facade 已补齐显式类型转发;strict frontier 当前覆盖 41 个文件,低水位只允许继续下降 | | Ruff 历史诊断 | 633 | 低水位门禁通过,但规则集只覆盖 `E4/E7/E9/F/I` | | 覆盖率低水位 | Application 81.61%,Domain 81.03% | Chain、Runtime、Agent、Adapter、Startup 未进入包级覆盖率门禁 | @@ -195,7 +195,7 @@ ARCH-204 均达到实现、验证、提交、推送和远端门禁闭环;S4/AR - Event consumer 扫描曾把任意同名 `.register()` 调用当成事件注册;S0-L2.5 已改为证明 canonical EventManager receiver,10 个动态误报归零并保留唯一 workflow 动态注册。 - S0-L2.6 已将 producer/consumer 合并为逐调用事实源;本轮统一 Transfer 事件发送点后为 - 93 个 producer(92 静态、1 动态)与 + 90 个 producer(89 静态、1 动态)与 17 个 consumer(16 静态、1 动态);consumer 由不可自动写入的精确人工 policy 管理。 **目标与步骤** diff --git a/docs/architecture/refactor-roadmap.md b/docs/architecture/refactor-roadmap.md index 017c21eae..56ab6b373 100644 --- a/docs/architecture/refactor-roadmap.md +++ b/docs/architecture/refactor-roadmap.md @@ -17,12 +17,12 @@ | Leaf | 状态 | 依赖 | 退出条件 | |---|---|---|---| -| R0 事实基线刷新 | `ACTIVE` | 无 | exact-head、远端、工作树、CI 和五类残余问题证据冻结;不修改 `app/plugins/**` | -| R1 System API 边界收口 | `PLANNED` | R0 | `system.py` 仅保留 HTTP/SSE/ZIP/响应映射;日志、Wiki、配置、事件、更新编排由 Application service/Port 拥有并由 startup 注入;旧 canonical 实现和重复导出删除 | -| R2 复杂度与原生并发门禁 | `PLANNED` | R0 | 扫描私有方法、类/文件热点及 `app/scheduler`;枚举全部 Thread/Timer/Executor/asyncio 原语;每条事实有 owner 或精确豁免,门禁不可绕过且本范围新增债务为零 | -| R3 Outbox after_commit 恢复语义 | `PLANNED` | R0 | after_commit 失败写入持久 intent;有唯一恢复 handler、claim/fencing、重启回放、幂等和失败可观测性;不得以内存 `pending_effects` 代替恢复 | -| R4 Startup/插件市场单一装配 | `PLANNED` | R0 | Transport、Adapter、Package、Dependency、Domain service 由 composition root 单一构造;initializer 和 market facade 不得隐式 new 第二套实例;SDK/Compat ABI 保持不变 | -| R5 验收与交付收口 | `PLANNED` | R1,R2,R3,R4 | 路线图、优化清单、规则和机器门禁一致;专项与锁定全量测试、Pylint、架构/兼容门禁、GitHub CI 通过;`HEAD == origin/v3` 且 ahead/behind 为 `0/0` | +| R0 事实基线刷新 | `DELIVERED` | 无 | `87269610e`:exact-head、远端、工作树、CI 和五类残余问题证据冻结;未修改 `app/plugins/**` | +| R1 System API 边界收口 | `DELIVERED` | R0 | `d50177f45`:日志、Wiki、配置、事件、更新与重启进入 `application/system.py` 和 `composition/system.py`;endpoint 只保留 HTTP/SSE/ZIP/响应映射 | +| R2 复杂度与原生并发门禁 | `DELIVERED` | R0 | `f7ca7e517`、`5cd5780d3`:完整 AST、Scheduler、canonical alias、TaskGroup、稳定 owner/count 与低水位门禁落地;本范围新增债务为零 | +| R3 Outbox after_commit 恢复语义 | `DELIVERED` | R0 | `9d06f91bb`:下载提交后通知、模块和字幕副作用改为同事务持久 intent,具备 handler、claim/fencing、重启回放、幂等与失败观测 | +| R4 Startup/插件市场单一装配 | `DELIVERED` | R0 | `7f5b8b469` 至 `046b0b305`:市场 Transport/Package/Dependency/Health、Domain、网络、站点、Chain、缓存、资源、DoH 和 Workflow 构造归入 composition;Compat 复用同一 owner | +| R5 验收与交付收口 | `ACTIVE` | R1,R2,R3,R4 | 路线图、优化清单、规则和机器门禁一致;专项与锁定全量测试、Pylint、架构/兼容门禁、GitHub CI 通过;`HEAD == origin/v3` 且 ahead/behind 为 `0/0` | 执行合同:任一时刻只允许一个 `ACTIVE` 叶子;每个叶子必须独立验证、显式提交和推送, 并在交付前复核插件 ABI、canonical 旧实现/重复导出和 `app/plugins/**` 排除边界。 @@ -391,7 +391,7 @@ TMDB、豆瓣、Bangumi、AniList 详情到统一字段的规则一次迁入 `ap service locator、mypy/Ruff ratchet、启动性能、Pylint `10.00/10` 与依赖一致性均通过。 - exact-head 失败后已将 canonical `SearchChain` Facade 改为显式类型转发,并修正 API/Workflow 的 Optional、Domain/Schema DTO 边界;2026-08-30 最终本地锁定全量 `7659 passed, 9 skipped`, - CI 同构架构测试 `197 passed`,mypy 低水位降至 `9,995`,Ruff、Pylint `10.00/10`、复杂度、 + CI 同构架构测试 `197 passed`,mypy 低水位降至 `9,987`,Ruff、Pylint `10.00/10`、复杂度、 async、TaskRegistry、service locator、启动性能与依赖快照门禁均通过。 - `4575b11d8` 修复 canonical `SearchChain` 类型转发并更新真实低水位,`c204e2e97` 修正架构测试对 Chain owner 的直接导入;两者均已推送并进入 `origin/v3` 祖先链。精确 head `c204e2e97` 的 diff --git a/tests/fixtures/architecture/dependency-baseline.json b/tests/fixtures/architecture/dependency-baseline.json index 3adb2ffe3..8d0111c59 100644 --- a/tests/fixtures/architecture/dependency-baseline.json +++ b/tests/fixtures/architecture/dependency-baseline.json @@ -1089,8 +1089,8 @@ "runtime_only": true } }, - "edge_count": 8357, - "edge_sha256": "e123a63c95486085c2155270fb78cc09c5309bf80bde0a92c5bf21878f83b39f", + "edge_count": 8416, + "edge_sha256": "f00ba5e6d21b301093d61c33e6ef33f15df9a672562176b140b9bf82db5acb9e", "edges": [ "app -> app.foundation", "app -> app.foundation.environment", @@ -1149,6 +1149,7 @@ "app.adapters.external.plugin.client -> app.domain.plugin", "app.adapters.external.plugin.client -> app.foundation", "app.adapters.external.plugin.client -> app.foundation.environment", + "app.adapters.external.plugin.client -> app.foundation.singleton", "app.adapters.external.plugin.client -> app.foundation.url", "app.adapters.external.plugin.client -> app.foundation.version", "app.adapters.external.plugin.client -> app.runtime", @@ -3452,21 +3453,9 @@ "app.api.endpoints.subscribe -> app.schemas.types", "app.api.endpoints.subscribe -> app.schemas.workflow", "app.api.endpoints.system -> app.adapters", - "app.api.endpoints.system -> app.adapters.external", - "app.api.endpoints.system -> app.adapters.external.plugin", - "app.api.endpoints.system -> app.adapters.external.plugin.client", - "app.api.endpoints.system -> app.adapters.external.server", - "app.api.endpoints.system -> app.adapters.network", - "app.api.endpoints.system -> app.adapters.network.http", - "app.api.endpoints.system -> app.adapters.system", - "app.api.endpoints.system -> app.adapters.system.rust", - "app.api.endpoints.system -> app.adapters.system.update", "app.api.endpoints.system -> app.adapters.web", "app.api.endpoints.system -> app.adapters.web.security", "app.api.endpoints.system -> app.adapters.web.security.access", - "app.api.endpoints.system -> app.agent", - "app.api.endpoints.system -> app.agent.llm", - "app.api.endpoints.system -> app.agent.llm.tools", "app.api.endpoints.system -> app.api", "app.api.endpoints.system -> app.api.context", "app.api.endpoints.system -> app.api.dependencies", @@ -3482,13 +3471,12 @@ "app.api.endpoints.system -> app.application.messaging.message", "app.api.endpoints.system -> app.application.module", "app.api.endpoints.system -> app.application.network", - "app.api.endpoints.system -> app.application.plugin", - "app.api.endpoints.system -> app.application.plugin.runtime", "app.api.endpoints.system -> app.application.rules", "app.api.endpoints.system -> app.application.scheduling", "app.api.endpoints.system -> app.application.security", "app.api.endpoints.system -> app.application.security.url", "app.api.endpoints.system -> app.application.site", + "app.api.endpoints.system -> app.application.system", "app.api.endpoints.system -> app.chain", "app.api.endpoints.system -> app.chain.media", "app.api.endpoints.system -> app.chain.mediaserver", @@ -3501,19 +3489,14 @@ "app.api.endpoints.system -> app.foundation.crypto", "app.api.endpoints.system -> app.foundation.environment", "app.api.endpoints.system -> app.runtime", - "app.api.endpoints.system -> app.runtime.events", "app.api.endpoints.system -> app.runtime.execution", "app.api.endpoints.system -> app.runtime.localization", "app.api.endpoints.system -> app.runtime.log", "app.api.endpoints.system -> app.runtime.progress", - "app.api.endpoints.system -> app.runtime.scheduling", - "app.api.endpoints.system -> app.runtime.state", "app.api.endpoints.system -> app.runtime.stop", "app.api.endpoints.system -> app.runtime.version", "app.api.endpoints.system -> app.schemas", "app.api.endpoints.system -> app.schemas.common", - "app.api.endpoints.system -> app.schemas.event", - "app.api.endpoints.system -> app.schemas.exception", "app.api.endpoints.system -> app.schemas.response", "app.api.endpoints.system -> app.schemas.system", "app.api.endpoints.system -> app.schemas.token", @@ -3755,6 +3738,7 @@ "app.application.chain.events -> app.domain.metainfo", "app.application.chain.events -> app.schemas", "app.application.chain.events -> app.schemas.file", + "app.application.chain.events -> app.schemas.message", "app.application.chain.events -> app.schemas.transfer", "app.application.chain.events -> app.schemas.types", "app.application.configuration -> app.application", @@ -4232,6 +4216,15 @@ "app.application.subscription.write -> app.schemas.common", "app.application.subscription.write -> app.schemas.media", "app.application.subscription.write -> app.schemas.types", + "app.application.system -> app.application", + "app.application.system -> app.application.configuration", + "app.application.system -> app.runtime", + "app.application.system -> app.runtime.scheduling", + "app.application.system -> app.schemas", + "app.application.system -> app.schemas.common", + "app.application.system -> app.schemas.exception", + "app.application.system -> app.schemas.system", + "app.application.system -> app.schemas.types", "app.application.torrent.cache -> app.domain", "app.application.torrent.cache -> app.domain.context", "app.application.torrent.cache -> app.domain.media", @@ -4471,6 +4464,8 @@ "app.chain.download.failure -> app.schemas", "app.chain.download.failure -> app.schemas.media", "app.chain.download.history -> app.application", + "app.chain.download.history -> app.application.chain", + "app.chain.download.history -> app.application.chain.events", "app.chain.download.history -> app.application.history", "app.chain.download.history -> app.chain", "app.chain.download.history -> app.chain.download", @@ -4485,6 +4480,9 @@ "app.chain.download.history -> app.schemas.types", "app.chain.download.ports -> app.runtime", "app.chain.download.ports -> app.runtime.log", + "app.chain.download.processing -> app.application", + "app.chain.download.processing -> app.application.messaging", + "app.chain.download.processing -> app.application.messaging.message", "app.chain.download.processing -> app.chain", "app.chain.download.processing -> app.chain.download", "app.chain.download.processing -> app.chain.download.contract", @@ -8691,16 +8689,28 @@ "app.startup.composition.agent -> app.startup.composition.database", "app.startup.composition.agent -> app.startup.composition.runtime", "app.startup.composition.agent -> app.startup.composition.subscription", + "app.startup.composition.cache -> app.adapters", + "app.startup.composition.cache -> app.adapters.cache", + "app.startup.composition.cache -> app.adapters.cache.backends", + "app.startup.composition.chain -> app.adapters", + "app.startup.composition.chain -> app.adapters.external", + "app.startup.composition.chain -> app.adapters.external.server", + "app.startup.composition.chain -> app.adapters.system", + "app.startup.composition.chain -> app.adapters.system.host", "app.startup.composition.chain -> app.application", "app.startup.composition.chain -> app.application.chain", "app.startup.composition.chain -> app.application.chain.context", "app.startup.composition.chain -> app.application.configuration", "app.startup.composition.chain -> app.application.image", "app.startup.composition.chain -> app.chain", + "app.startup.composition.chain -> app.chain._recognition", "app.startup.composition.chain -> app.chain.mediaserver", + "app.startup.composition.chain -> app.chain.subscribe", + "app.startup.composition.chain -> app.chain.subscribe.notify", "app.startup.composition.chain -> app.chain.tmdb", "app.startup.composition.chain -> app.chain.transfer", "app.startup.composition.chain -> app.chain.transfer.facade", + "app.startup.composition.chain -> app.chain.transfer.filter", "app.startup.composition.chain -> app.db", "app.startup.composition.chain -> app.db.adapters", "app.startup.composition.chain -> app.db.adapters.chain", @@ -8712,6 +8722,10 @@ "app.startup.composition.chain -> app.db.oper.message", "app.startup.composition.chain -> app.db.oper.systemconfig", "app.startup.composition.chain -> app.db.session", + "app.startup.composition.chain -> app.domain", + "app.startup.composition.chain -> app.domain.context", + "app.startup.composition.chain -> app.domain.meta", + "app.startup.composition.chain -> app.domain.meta.metabase", "app.startup.composition.chain -> app.runtime", "app.startup.composition.chain -> app.runtime.cache", "app.startup.composition.chain -> app.runtime.events", @@ -8722,6 +8736,9 @@ "app.startup.composition.chain -> app.runtime.extensions.plugin", "app.startup.composition.chain -> app.runtime.extensions.plugin.manager", "app.startup.composition.chain -> app.runtime.stop", + "app.startup.composition.chain -> app.schemas", + "app.startup.composition.chain -> app.schemas.common", + "app.startup.composition.chain -> app.schemas.types", "app.startup.composition.chain -> app.startup", "app.startup.composition.chain -> app.startup.composition", "app.startup.composition.chain -> app.startup.composition.database", @@ -8757,6 +8774,7 @@ "app.startup.composition.context -> app.application.subscription", "app.startup.composition.context -> app.application.subscription.contract", "app.startup.composition.context -> app.application.subscription.write", + "app.startup.composition.context -> app.application.system", "app.startup.composition.context -> app.application.transfer", "app.startup.composition.context -> app.application.transfer.execution", "app.startup.composition.context -> app.application.workflow", @@ -8793,16 +8811,51 @@ "app.startup.composition.database -> app.db.worker", "app.startup.composition.database -> app.runtime", "app.startup.composition.database -> app.runtime.settings", + "app.startup.composition.domain -> app.adapters", + "app.startup.composition.domain -> app.adapters.network", + "app.startup.composition.domain -> app.adapters.network.resolver", + "app.startup.composition.domain -> app.adapters.system", + "app.startup.composition.domain -> app.adapters.system.host", + "app.startup.composition.domain -> app.adapters.system.rust", + "app.startup.composition.domain -> app.application", + "app.startup.composition.domain -> app.application.directory", + "app.startup.composition.domain -> app.application.recognition", + "app.startup.composition.domain -> app.application.rules", + "app.startup.composition.domain -> app.application.security", + "app.startup.composition.domain -> app.application.security.url", + "app.startup.composition.domain -> app.application.transfer", + "app.startup.composition.domain -> app.application.transfer.workflow", + "app.startup.composition.domain -> app.domain", + "app.startup.composition.domain -> app.domain.media", + "app.startup.composition.domain -> app.domain.meta", + "app.startup.composition.domain -> app.domain.meta.customization", + "app.startup.composition.domain -> app.domain.meta.releasegroup", + "app.startup.composition.domain -> app.domain.meta.runtime", + "app.startup.composition.domain -> app.domain.meta.words", + "app.startup.composition.domain -> app.domain.metainfo", + "app.startup.composition.domain -> app.domain.projection", + "app.startup.composition.domain -> app.domain.projection.tmdb", + "app.startup.composition.domain -> app.runtime", + "app.startup.composition.domain -> app.runtime.settings", "app.startup.composition.network -> app.adapters", "app.startup.composition.network -> app.adapters.network", + "app.startup.composition.network -> app.adapters.network.doh", "app.startup.composition.network -> app.adapters.network.http", "app.startup.composition.network -> app.adapters.network.ip", + "app.startup.composition.network -> app.adapters.system", + "app.startup.composition.network -> app.adapters.system.host", "app.startup.composition.network -> app.application", "app.startup.composition.network -> app.application.configuration", "app.startup.composition.network -> app.application.image", "app.startup.composition.network -> app.application.messaging", "app.startup.composition.network -> app.application.messaging.ingress", "app.startup.composition.network -> app.application.network", + "app.startup.composition.network -> app.chain", + "app.startup.composition.network -> app.chain.download", + "app.startup.composition.network -> app.chain.download.ports", + "app.startup.composition.network -> app.chain.message", + "app.startup.composition.network -> app.chain.scraping", + "app.startup.composition.network -> app.chain.system", "app.startup.composition.network -> app.runtime", "app.startup.composition.network -> app.runtime.log", "app.startup.composition.outbox -> app.adapters", @@ -8812,17 +8865,40 @@ "app.startup.composition.outbox -> app.application.chain", "app.startup.composition.outbox -> app.application.chain.events", "app.startup.composition.outbox -> app.application.outbox", + "app.startup.composition.outbox -> app.chain", + "app.startup.composition.outbox -> app.chain.download", "app.startup.composition.outbox -> app.command", "app.startup.composition.outbox -> app.db", "app.startup.composition.outbox -> app.db.adapters", "app.startup.composition.outbox -> app.db.adapters.outbox", "app.startup.composition.outbox -> app.db.session", "app.startup.composition.outbox -> app.runtime", + "app.startup.composition.outbox -> app.runtime.correlation", "app.startup.composition.outbox -> app.runtime.events", "app.startup.composition.outbox -> app.runtime.observability", "app.startup.composition.outbox -> app.schemas", "app.startup.composition.outbox -> app.schemas.message", "app.startup.composition.outbox -> app.schemas.types", + "app.startup.composition.plugin -> app.adapters", + "app.startup.composition.plugin -> app.adapters.external", + "app.startup.composition.plugin -> app.adapters.external.plugin", + "app.startup.composition.plugin -> app.adapters.external.plugin.client", + "app.startup.composition.plugin -> app.adapters.system", + "app.startup.composition.plugin -> app.adapters.system.plugin", + "app.startup.composition.plugin -> app.adapters.system.plugin.dependency", + "app.startup.composition.plugin -> app.adapters.system.plugin.health", + "app.startup.composition.plugin -> app.adapters.system.plugin.package", + "app.startup.composition.plugin -> app.runtime", + "app.startup.composition.plugin -> app.runtime.settings", + "app.startup.composition.resource -> app.adapters", + "app.startup.composition.resource -> app.adapters.system", + "app.startup.composition.resource -> app.adapters.system.resource", + "app.startup.composition.resource -> app.runtime", + "app.startup.composition.resource -> app.runtime.capabilities", + "app.startup.composition.resource -> app.runtime.capabilities.runtime", + "app.startup.composition.resource -> app.runtime.extensions", + "app.startup.composition.resource -> app.runtime.extensions.resource", + "app.startup.composition.resource -> app.runtime.resources", "app.startup.composition.runtime -> app.api", "app.startup.composition.runtime -> app.api.data", "app.startup.composition.runtime -> app.application", @@ -8859,6 +8935,7 @@ "app.startup.composition.runtime -> app.startup.composition", "app.startup.composition.runtime -> app.startup.composition.context", "app.startup.composition.runtime -> app.startup.composition.subscription", + "app.startup.composition.runtime -> app.startup.composition.system", "app.startup.composition.security -> app.adapters", "app.startup.composition.security -> app.adapters.web", "app.startup.composition.security -> app.adapters.web.security", @@ -8894,6 +8971,24 @@ "app.startup.composition.server -> app.application.workflow", "app.startup.composition.server -> app.schemas", "app.startup.composition.server -> app.schemas.types", + "app.startup.composition.site -> app.adapters", + "app.startup.composition.site -> app.adapters.external", + "app.startup.composition.site -> app.adapters.external.cookiecloud", + "app.startup.composition.site -> app.adapters.external.ocr", + "app.startup.composition.site -> app.adapters.network", + "app.startup.composition.site -> app.adapters.network.browser", + "app.startup.composition.site -> app.adapters.network.cloudflare", + "app.startup.composition.site -> app.adapters.network.http", + "app.startup.composition.site -> app.adapters.system", + "app.startup.composition.site -> app.adapters.system.rust", + "app.startup.composition.site -> app.application", + "app.startup.composition.site -> app.application.rss", + "app.startup.composition.site -> app.application.security", + "app.startup.composition.site -> app.application.security.cookie", + "app.startup.composition.site -> app.application.torrent", + "app.startup.composition.site -> app.application.torrent.download", + "app.startup.composition.site -> app.chain", + "app.startup.composition.site -> app.chain.site", "app.startup.composition.subscription -> app.adapters", "app.startup.composition.subscription -> app.adapters.external", "app.startup.composition.subscription -> app.adapters.external.server", @@ -8920,6 +9015,34 @@ "app.startup.composition.subscription -> app.schemas", "app.startup.composition.subscription -> app.schemas.common", "app.startup.composition.subscription -> app.schemas.types", + "app.startup.composition.system -> app.adapters", + "app.startup.composition.system -> app.adapters.external", + "app.startup.composition.system -> app.adapters.external.plugin", + "app.startup.composition.system -> app.adapters.external.plugin.client", + "app.startup.composition.system -> app.adapters.external.server", + "app.startup.composition.system -> app.adapters.network", + "app.startup.composition.system -> app.adapters.network.http", + "app.startup.composition.system -> app.adapters.system", + "app.startup.composition.system -> app.adapters.system.rust", + "app.startup.composition.system -> app.adapters.system.update", + "app.startup.composition.system -> app.agent", + "app.startup.composition.system -> app.agent.llm", + "app.startup.composition.system -> app.agent.llm.tools", + "app.startup.composition.system -> app.application", + "app.startup.composition.system -> app.application.configuration", + "app.startup.composition.system -> app.application.plugin", + "app.startup.composition.system -> app.application.plugin.runtime", + "app.startup.composition.system -> app.application.security", + "app.startup.composition.system -> app.application.security.url", + "app.startup.composition.system -> app.application.system", + "app.startup.composition.system -> app.runtime", + "app.startup.composition.system -> app.runtime.events", + "app.startup.composition.system -> app.runtime.state", + "app.startup.composition.system -> app.runtime.stop", + "app.startup.composition.system -> app.schemas", + "app.startup.composition.system -> app.schemas.event", + "app.startup.composition.system -> app.schemas.system", + "app.startup.composition.system -> app.schemas.types", "app.startup.initializers.agent -> app.agent", "app.startup.initializers.agent -> app.agent.llm", "app.startup.initializers.agent -> app.agent.llm.capability", @@ -8948,27 +9071,12 @@ "app.startup.initializers.agent -> app.runtime.settings", "app.startup.initializers.agent -> app.schemas", "app.startup.initializers.agent -> app.schemas.types", - "app.startup.initializers.cache -> app.adapters", - "app.startup.initializers.cache -> app.adapters.cache", - "app.startup.initializers.cache -> app.adapters.cache.backends", - "app.startup.initializers.chain -> app.adapters", - "app.startup.initializers.chain -> app.adapters.external", - "app.startup.initializers.chain -> app.adapters.external.server", - "app.startup.initializers.chain -> app.adapters.system", - "app.startup.initializers.chain -> app.adapters.system.host", - "app.startup.initializers.chain -> app.chain", - "app.startup.initializers.chain -> app.chain._recognition", - "app.startup.initializers.chain -> app.chain.subscribe", - "app.startup.initializers.chain -> app.chain.subscribe.notify", - "app.startup.initializers.chain -> app.chain.transfer", - "app.startup.initializers.chain -> app.chain.transfer.filter", - "app.startup.initializers.chain -> app.domain", - "app.startup.initializers.chain -> app.domain.context", - "app.startup.initializers.chain -> app.domain.meta", - "app.startup.initializers.chain -> app.domain.meta.metabase", - "app.startup.initializers.chain -> app.schemas", - "app.startup.initializers.chain -> app.schemas.common", - "app.startup.initializers.chain -> app.schemas.types", + "app.startup.initializers.cache -> app.startup", + "app.startup.initializers.cache -> app.startup.composition", + "app.startup.initializers.cache -> app.startup.composition.cache", + "app.startup.initializers.chain -> app.startup", + "app.startup.initializers.chain -> app.startup.composition", + "app.startup.initializers.chain -> app.startup.composition.chain", "app.startup.initializers.command -> app.application", "app.startup.initializers.command -> app.application.commands", "app.startup.initializers.command -> app.command", @@ -8982,32 +9090,9 @@ "app.startup.initializers.database -> app.startup", "app.startup.initializers.database -> app.startup.composition", "app.startup.initializers.database -> app.startup.composition.database", - "app.startup.initializers.domain -> app.adapters", - "app.startup.initializers.domain -> app.adapters.network", - "app.startup.initializers.domain -> app.adapters.network.resolver", - "app.startup.initializers.domain -> app.adapters.system", - "app.startup.initializers.domain -> app.adapters.system.host", - "app.startup.initializers.domain -> app.adapters.system.rust", - "app.startup.initializers.domain -> app.application", - "app.startup.initializers.domain -> app.application.directory", - "app.startup.initializers.domain -> app.application.recognition", - "app.startup.initializers.domain -> app.application.rules", - "app.startup.initializers.domain -> app.application.security", - "app.startup.initializers.domain -> app.application.security.url", - "app.startup.initializers.domain -> app.application.transfer", - "app.startup.initializers.domain -> app.application.transfer.workflow", - "app.startup.initializers.domain -> app.domain", - "app.startup.initializers.domain -> app.domain.media", - "app.startup.initializers.domain -> app.domain.meta", - "app.startup.initializers.domain -> app.domain.meta.customization", - "app.startup.initializers.domain -> app.domain.meta.releasegroup", - "app.startup.initializers.domain -> app.domain.meta.runtime", - "app.startup.initializers.domain -> app.domain.meta.words", - "app.startup.initializers.domain -> app.domain.metainfo", - "app.startup.initializers.domain -> app.domain.projection", - "app.startup.initializers.domain -> app.domain.projection.tmdb", - "app.startup.initializers.domain -> app.runtime", - "app.startup.initializers.domain -> app.runtime.settings", + "app.startup.initializers.domain -> app.startup", + "app.startup.initializers.domain -> app.startup.composition", + "app.startup.initializers.domain -> app.startup.composition.domain", "app.startup.initializers.modules -> app.adapters", "app.startup.initializers.modules -> app.adapters.cache", "app.startup.initializers.modules -> app.adapters.cache.redis", @@ -9015,10 +9100,8 @@ "app.startup.initializers.modules -> app.adapters.external.server", "app.startup.initializers.modules -> app.adapters.network", "app.startup.initializers.modules -> app.adapters.network.browser", - "app.startup.initializers.modules -> app.adapters.network.doh", "app.startup.initializers.modules -> app.adapters.system", "app.startup.initializers.modules -> app.adapters.system.host", - "app.startup.initializers.modules -> app.adapters.system.resource", "app.startup.initializers.modules -> app.agent", "app.startup.initializers.modules -> app.agent.tools", "app.startup.initializers.modules -> app.agent.tools.manager", @@ -9034,7 +9117,6 @@ "app.startup.initializers.modules -> app.application.security.url", "app.startup.initializers.modules -> app.application.service", "app.startup.initializers.modules -> app.application.site", - "app.startup.initializers.modules -> app.application.workflow", "app.startup.initializers.modules -> app.chain", "app.startup.initializers.modules -> app.chain.download", "app.startup.initializers.modules -> app.chain.scraping", @@ -9046,8 +9128,6 @@ "app.startup.initializers.modules -> app.chain.workflow", "app.startup.initializers.modules -> app.command", "app.startup.initializers.modules -> app.db", - "app.startup.initializers.modules -> app.db.adapters", - "app.startup.initializers.modules -> app.db.adapters.workflow", "app.startup.initializers.modules -> app.db.session", "app.startup.initializers.modules -> app.runtime", "app.startup.initializers.modules -> app.runtime.config", @@ -9076,6 +9156,7 @@ "app.startup.initializers.modules -> app.startup.composition.database", "app.startup.initializers.modules -> app.startup.composition.network", "app.startup.initializers.modules -> app.startup.composition.outbox", + "app.startup.initializers.modules -> app.startup.composition.resource", "app.startup.initializers.modules -> app.startup.composition.runtime", "app.startup.initializers.modules -> app.startup.composition.security", "app.startup.initializers.modules -> app.startup.composition.server", @@ -9086,17 +9167,9 @@ "app.startup.initializers.monitor -> app.monitor", "app.startup.initializers.monitor -> app.runtime", "app.startup.initializers.monitor -> app.runtime.execution", - "app.startup.initializers.network -> app.adapters", - "app.startup.initializers.network -> app.adapters.network", - "app.startup.initializers.network -> app.adapters.network.http", - "app.startup.initializers.network -> app.adapters.system", - "app.startup.initializers.network -> app.adapters.system.host", - "app.startup.initializers.network -> app.chain", - "app.startup.initializers.network -> app.chain.download", - "app.startup.initializers.network -> app.chain.download.ports", - "app.startup.initializers.network -> app.chain.message", - "app.startup.initializers.network -> app.chain.scraping", - "app.startup.initializers.network -> app.chain.system", + "app.startup.initializers.network -> app.startup", + "app.startup.initializers.network -> app.startup.composition", + "app.startup.initializers.network -> app.startup.composition.network", "app.startup.initializers.plugins -> app.adapters", "app.startup.initializers.plugins -> app.adapters.external", "app.startup.initializers.plugins -> app.adapters.external.market", @@ -9106,9 +9179,7 @@ "app.startup.initializers.plugins -> app.adapters.system", "app.startup.initializers.plugins -> app.adapters.system.host", "app.startup.initializers.plugins -> app.adapters.system.plugin", - "app.startup.initializers.plugins -> app.adapters.system.plugin.dependency", "app.startup.initializers.plugins -> app.adapters.system.plugin.manifest", - "app.startup.initializers.plugins -> app.adapters.system.plugin.package", "app.startup.initializers.plugins -> app.application", "app.startup.initializers.plugins -> app.application.commands", "app.startup.initializers.plugins -> app.application.configuration", @@ -9157,12 +9228,15 @@ "app.startup.initializers.plugins -> app.schemas.exception", "app.startup.initializers.plugins -> app.schemas.plugin", "app.startup.initializers.plugins -> app.schemas.types", + "app.startup.initializers.plugins -> app.startup", + "app.startup.initializers.plugins -> app.startup.composition", + "app.startup.initializers.plugins -> app.startup.composition.plugin", "app.startup.initializers.resources -> app.runtime", "app.startup.initializers.resources -> app.runtime.capabilities", "app.startup.initializers.resources -> app.runtime.capabilities.runtime", - "app.startup.initializers.resources -> app.runtime.extensions", - "app.startup.initializers.resources -> app.runtime.extensions.resource", - "app.startup.initializers.resources -> app.runtime.resources", + "app.startup.initializers.resources -> app.startup", + "app.startup.initializers.resources -> app.startup.composition", + "app.startup.initializers.resources -> app.startup.composition.resource", "app.startup.initializers.routers -> app.api", "app.startup.initializers.routers -> app.api.routers", "app.startup.initializers.routers -> app.api.servarr", @@ -9184,24 +9258,9 @@ "app.startup.initializers.scheduler -> app.scheduler.chain", "app.startup.initializers.scheduler -> app.scheduler.facade", "app.startup.initializers.scheduler -> app.scheduler.services", - "app.startup.initializers.site -> app.adapters", - "app.startup.initializers.site -> app.adapters.external", - "app.startup.initializers.site -> app.adapters.external.cookiecloud", - "app.startup.initializers.site -> app.adapters.external.ocr", - "app.startup.initializers.site -> app.adapters.network", - "app.startup.initializers.site -> app.adapters.network.browser", - "app.startup.initializers.site -> app.adapters.network.cloudflare", - "app.startup.initializers.site -> app.adapters.network.http", - "app.startup.initializers.site -> app.adapters.system", - "app.startup.initializers.site -> app.adapters.system.rust", - "app.startup.initializers.site -> app.application", - "app.startup.initializers.site -> app.application.rss", - "app.startup.initializers.site -> app.application.security", - "app.startup.initializers.site -> app.application.security.cookie", - "app.startup.initializers.site -> app.application.torrent", - "app.startup.initializers.site -> app.application.torrent.download", - "app.startup.initializers.site -> app.chain", - "app.startup.initializers.site -> app.chain.site", + "app.startup.initializers.site -> app.startup", + "app.startup.initializers.site -> app.startup.composition", + "app.startup.initializers.site -> app.startup.composition.site", "app.startup.initializers.transfer -> app.chain", "app.startup.initializers.transfer -> app.chain.transfer", "app.startup.initializers.transfer -> app.chain.transfer.facade", @@ -9450,7 +9509,7 @@ "app.workflow.actions.transfer_file -> app.workflow", "app.workflow.actions.transfer_file -> app.workflow.actions" ], - "module_count": 974, + "module_count": 981, "modules": [ "app", "app.adapters", @@ -9809,6 +9868,7 @@ "app.application.subscription.query", "app.application.subscription.search", "app.application.subscription.write", + "app.application.system", "app.application.torrent", "app.application.torrent.cache", "app.application.torrent.download", @@ -10376,16 +10436,22 @@ "app.startup", "app.startup.composition", "app.startup.composition.agent", + "app.startup.composition.cache", "app.startup.composition.chain", "app.startup.composition.configuration", "app.startup.composition.context", "app.startup.composition.database", + "app.startup.composition.domain", "app.startup.composition.network", "app.startup.composition.outbox", + "app.startup.composition.plugin", + "app.startup.composition.resource", "app.startup.composition.runtime", "app.startup.composition.security", "app.startup.composition.server", + "app.startup.composition.site", "app.startup.composition.subscription", + "app.startup.composition.system", "app.startup.initializers", "app.startup.initializers.agent", "app.startup.initializers.cache", diff --git a/tests/fixtures/architecture/runtime-contract-baseline.json b/tests/fixtures/architecture/runtime-contract-baseline.json index a098a3fd8..e06b7ec8e 100644 --- a/tests/fixtures/architecture/runtime-contract-baseline.json +++ b/tests/fixtures/architecture/runtime-contract-baseline.json @@ -1764,11 +1764,8 @@ "c53927bd5752ec004ac403f6dc07fca7b253f0db152fc773643972d7c3bf5d34" ], "producer_fingerprints": [ - "14564c7ef4f2057a2a03bd0070cafe7c5421184ae7b2c28d5f9735722691337c", + "36d3234c5f3cd7317c34d6ee71bc065946ea0e981dd2377589f73e54ebaf8703", "5fe23577466054d66cb12b34d4df8834f8933596be0cbc84e4cbfc22694b3c03", - "6c5b8155f0e6ff9ed879b8ea43904ea05c74f81762d6ae87c71de40673a5629b", - "91ec6e0454403b22f1ddc7cb6e4fc9414df8a00892e615131e41ff0599618dce", - "91ec6e0454403b22f1ddc7cb6e4fc9414df8a00892e615131e41ff0599618dce", "cdf41d4446e65b14d457621594f04b3e6bfce252e7701cb4be862b2259e97700" ] }, @@ -1966,11 +1963,11 @@ ] } }, - "fact_count": 110, + "fact_count": 107, "invalid_consumer_count": 0, "invalid_producer_count": 0, - "producer_call_count": 93, - "producer_event_reference_count": 94, + "producer_call_count": 90, + "producer_event_reference_count": 91, "producers": [ { "caller": "app.agent.orchestrator", @@ -2140,54 +2137,6 @@ "qualname": "source", "receiver_kind": "canonical_singleton" }, - { - "caller": "app.api.endpoints.system", - "dynamic": false, - "events": [ - "EventType.ConfigChanged" - ], - "fingerprint": "6c5b8155f0e6ff9ed879b8ea43904ea05c74f81762d6ae87c71de40673a5629b", - "invalid": false, - "method": "async_send_event", - "qualname": "set_env_setting", - "receiver_kind": "canonical_singleton" - }, - { - "caller": "app.api.endpoints.system", - "dynamic": false, - "events": [ - "EventType.ConfigChanged" - ], - "fingerprint": "91ec6e0454403b22f1ddc7cb6e4fc9414df8a00892e615131e41ff0599618dce", - "invalid": false, - "method": "async_send_event", - "qualname": "set_setting", - "receiver_kind": "canonical_singleton" - }, - { - "caller": "app.api.endpoints.system", - "dynamic": false, - "events": [ - "EventType.ConfigChanged" - ], - "fingerprint": "91ec6e0454403b22f1ddc7cb6e4fc9414df8a00892e615131e41ff0599618dce", - "invalid": false, - "method": "async_send_event", - "qualname": "set_setting", - "receiver_kind": "canonical_singleton" - }, - { - "caller": "app.api.endpoints.system", - "dynamic": false, - "events": [ - "EventType.ConfigChanged" - ], - "fingerprint": "14564c7ef4f2057a2a03bd0070cafe7c5421184ae7b2c28d5f9735722691337c", - "invalid": false, - "method": "async_send_event", - "qualname": "sync_plugin_market_from_wiki", - "receiver_kind": "canonical_singleton" - }, { "caller": "app.application.messaging.plugin", "dynamic": false, @@ -3052,6 +3001,18 @@ "qualname": "_publish_modified_sync", "receiver_kind": "canonical_singleton" }, + { + "caller": "app.startup.composition.system", + "dynamic": false, + "events": [ + "EventType.ConfigChanged" + ], + "fingerprint": "36d3234c5f3cd7317c34d6ee71bc065946ea0e981dd2377589f73e54ebaf8703", + "invalid": false, + "method": "async_send_event", + "qualname": "_ConfigurationEventAdapter.publish", + "receiver_kind": "canonical_singleton" + }, { "caller": "app.workflow", "dynamic": false, @@ -3090,7 +3051,7 @@ } ], "static_consumer_count": 16, - "static_producer_call_count": 92 + "static_producer_call_count": 89 }, "event_specs": { "ChainEventType.AgentLLMProvider": { diff --git a/tests/test_acceleration.py b/tests/test_acceleration.py index 77af7385e..a91710a74 100644 --- a/tests/test_acceleration.py +++ b/tests/test_acceleration.py @@ -9,7 +9,7 @@ import pytest from app.application import directory as directory_module from app.application import rules as rules_module from app.application.transfer import workflow as workflow_module -from app.startup.initializers import domain as domain_initializer +from app.startup.composition import domain as domain_composition def test_directory_helper_requires_configured_topology_for_local_paths( @@ -109,14 +109,14 @@ def test_job_task_size_requires_reader_for_missing_local_size(monkeypatch) -> No workflow_module._job_task_size(local) -def test_domain_initializer_injects_all_system_acceleration_ports(monkeypatch) -> None: +def test_domain_composition_injects_all_system_acceleration_ports(monkeypatch) -> None: """领域组合根必须显式注入拓扑、规则解析和目录大小三个端口。""" disk = MagicMock() parser = MagicMock() size = MagicMock() - monkeypatch.setattr(domain_initializer, "configure_disk_topology", disk) - monkeypatch.setattr(domain_initializer, "configure_filter_rule_parser", parser) - monkeypatch.setattr(domain_initializer, "configure_directory_size", size) + monkeypatch.setattr(domain_composition, "configure_disk_topology", disk) + monkeypatch.setattr(domain_composition, "configure_filter_rule_parser", parser) + monkeypatch.setattr(domain_composition, "configure_directory_size", size) for name in ( "configure_dns_resolver", "configure_customization_provider", @@ -126,20 +126,20 @@ def test_domain_initializer_injects_all_system_acceleration_ports(monkeypatch) - "configure_recognition_runtime", "clear_rust_parse_options_cache", ): - monkeypatch.setattr(domain_initializer, name, MagicMock()) + monkeypatch.setattr(domain_composition, name, MagicMock()) monkeypatch.setattr( "app.domain.projection.tmdb.configure_image_url_builder", MagicMock(), ) - monkeypatch.setattr(domain_initializer, "RecognitionRuleService", MagicMock()) + monkeypatch.setattr(domain_composition, "RecognitionRuleService", MagicMock()) monkeypatch.setattr( - domain_initializer, + domain_composition, "get_runtime_setting", MagicMock(return_value=()), ) - domain_initializer.configure_domain_dependencies() + domain_composition.compose_domain_dependencies() - disk.assert_called_once_with(domain_initializer.SystemUtils) - parser.assert_called_once_with(domain_initializer.rust_accelerator) - size.assert_called_once_with(domain_initializer.SystemUtils) + disk.assert_called_once_with(domain_composition.SystemUtils) + parser.assert_called_once_with(domain_composition.rust_accelerator) + size.assert_called_once_with(domain_composition.SystemUtils) diff --git a/tests/test_agent_lifecycle.py b/tests/test_agent_lifecycle.py index 5acc6d82a..da76e79ae 100644 --- a/tests/test_agent_lifecycle.py +++ b/tests/test_agent_lifecycle.py @@ -172,12 +172,12 @@ async def test_agent_initialization_failure_does_not_stop_module_startup( monkeypatch.setattr(modules_initializer, "init_agent", agent_initializer.init_agent) for name in ( - "DohHelper", "SitesHelper", - "ResourceHelper", "ModuleManager", ): monkeypatch.setattr(modules_initializer, name, MagicMock()) + monkeypatch.setattr(modules_initializer, "configure_doh_composition", MagicMock()) + monkeypatch.setattr(modules_initializer, "update_resources", MagicMock()) monkeypatch.setattr(modules_initializer, "init_managed_resources", MagicMock()) monkeypatch.setattr(modules_initializer, "user_auth", MagicMock()) monkeypatch.setattr(modules_initializer.EventManager, "start", MagicMock()) diff --git a/tests/test_architecture_contract_baseline.py b/tests/test_architecture_contract_baseline.py index 74c0d3b82..e0b99ac48 100644 --- a/tests/test_architecture_contract_baseline.py +++ b/tests/test_architecture_contract_baseline.py @@ -469,17 +469,17 @@ def test_event_contract_baseline_covers_every_public_event_enum() -> None: assert set(events["event_index"]) == expected assert events["event_count"] == len(expected) - assert events["producer_call_count"] == 93 - assert events["static_producer_call_count"] == 92 + assert events["producer_call_count"] == 90 + assert events["static_producer_call_count"] == 89 assert events["dynamic_producer_count"] == 1 assert events["invalid_producer_count"] == 0 - assert events["producer_event_reference_count"] == 94 + assert events["producer_event_reference_count"] == 91 assert events["consumer_registration_count"] == 17 assert events["static_consumer_count"] == 16 assert events["dynamic_consumer_count"] == 1 assert events["invalid_consumer_count"] == 0 assert events["consumer_event_reference_count"] == 16 - assert events["fact_count"] == 110 + assert events["fact_count"] == 107 assert len({fact["fingerprint"] for fact in events["consumers"]}) == 17 assert all( not fact["caller"].startswith("app.plugins") diff --git a/tests/test_architecture_dependencies.py b/tests/test_architecture_dependencies.py index 3ad71b59a..e8cd7d68a 100644 --- a/tests/test_architecture_dependencies.py +++ b/tests/test_architecture_dependencies.py @@ -612,9 +612,11 @@ def test_workflow_execution_chain_uses_single_application_owned_port(): chain_source = (APP_ROOT / "chain" / "workflow.py").read_text(encoding="utf-8") startup_source = (APP_ROOT / "startup" / "initializers" / "modules.py").read_text(encoding="utf-8") + composition_source = (APP_ROOT / "startup" / "composition" / "database.py").read_text(encoding="utf-8") assert chain_source.count("get_configured_workflow_execution()") == 1 assert "get_chain_workflow_port" not in chain_source - assert "configure_workflow_execution(workflow_execution)" in startup_source + assert "configure_workflow_execution(TransactionalWorkflowExecutionService(SessionFactory))" in composition_source + assert "configure_workflow_execution_composition()" in startup_source assert "workflow=lambda:" not in startup_source diff --git a/tests/test_architecture_event_facts.py b/tests/test_architecture_event_facts.py index 22ec725e1..4a0a9dcf4 100644 --- a/tests/test_architecture_event_facts.py +++ b/tests/test_architecture_event_facts.py @@ -1142,7 +1142,7 @@ def handler(event): def test_collect_event_facts_matches_current_host_inventory() -> None: - """统一事实覆盖当前 93 个 producer 调用与 17 个 consumer 调用。""" + """统一事实覆盖当前 90 个 producer 调用与 17 个 consumer 调用。""" from scripts.architecture.baseline import ( _event_enum_members, discover_modules, @@ -1158,11 +1158,11 @@ def test_collect_event_facts_matches_current_host_inventory() -> None: producers = facts["producers"] consumers = facts["consumers"] - assert len(producers) == 93 - assert sum(not fact["dynamic"] and not fact["invalid"] for fact in producers) == 92 + assert len(producers) == 90 + assert sum(not fact["dynamic"] and not fact["invalid"] for fact in producers) == 89 assert sum(fact["dynamic"] for fact in producers) == 1 assert sum(fact["invalid"] for fact in producers) == 0 - assert sum(len(fact["events"]) for fact in producers) == 94 + assert sum(len(fact["events"]) for fact in producers) == 91 assert len(consumers) == 17 assert sum(not fact["dynamic"] and not fact["invalid"] for fact in consumers) == 16 assert sum(fact["dynamic"] for fact in consumers) == 1 diff --git a/tests/test_cache_system.py b/tests/test_cache_system.py index 1fefb3d9f..55fd1f8dd 100644 --- a/tests/test_cache_system.py +++ b/tests/test_cache_system.py @@ -3,7 +3,6 @@ import os import threading import time from concurrent.futures import ThreadPoolExecutor -from types import SimpleNamespace from unittest.mock import AsyncMock import pytest @@ -148,13 +147,9 @@ def test_init_modules_does_not_clear_package_tool_cache(monkeypatch): monkeypatch.setattr(modules_initializer, "clear_package_tool_cache", fail_if_called) monkeypatch.setattr(modules_initializer, "init_managed_resources", lambda: None) - monkeypatch.setattr(modules_initializer, "DohHelper", lambda: None) + monkeypatch.setattr(modules_initializer, "configure_doh_composition", lambda: None) monkeypatch.setattr(modules_initializer, "SitesHelper", lambda: None) - monkeypatch.setattr( - modules_initializer, - "ResourceHelper", - lambda: SimpleNamespace(check=lambda: False), - ) + monkeypatch.setattr(modules_initializer, "update_resources", lambda: None) monkeypatch.setattr(modules_initializer, "user_auth", lambda: None) monkeypatch.setattr(modules_initializer, "ModuleManager", lambda: None) monkeypatch.setattr(modules_initializer.EventManager, "start", lambda self: None) diff --git a/tests/test_download_chain.py b/tests/test_download_chain.py index c0c2e74fb..82e209b93 100644 --- a/tests/test_download_chain.py +++ b/tests/test_download_chain.py @@ -390,7 +390,7 @@ def test_save_subtitle_response_accepts_rar_filename_from_header(monkeypatch, tm monkeypatch.setattr(download_subtitle, "StorageChain", lambda: storage_chain) monkeypatch.setattr( - "app.startup.initializers.network.SystemUtils.unpack_archive", + "app.adapters.system.host.SystemUtils.unpack_archive", fake_unpack_archive, ) diff --git a/tests/test_mediascrape.py b/tests/test_mediascrape.py index ea28d8057..543925519 100644 --- a/tests/test_mediascrape.py +++ b/tests/test_mediascrape.py @@ -417,7 +417,7 @@ class TestMediaScrapingImages(unittest.TestCase): self.assertEqual(target_item, fileitem) self.assertEqual(target_path, Path("/tv/Show/Season 1/backdrop.jpg")) - @patch("app.startup.initializers.network.RequestUtils") + @patch("app.chain.scraping._scraping_http_snapshot") @patch("app.chain.scraping.NamedTemporaryFile") @patch("app.chain.scraping.Path.chmod") def test_download_and_save_image(self, mock_chmod, mock_temp_file, mock_request_utils): @@ -442,16 +442,17 @@ class TestMediaScrapingImages(unittest.TestCase): mock_instance = mock_request_utils.return_value mock_instance.get_stream.return_value.__enter__.return_value = mock_stream + mock_instance.stream.return_value.__enter__.return_value = mock_stream self.media_chain.storagechain.upload_file.return_value = fileitem self.media_chain._download_and_save_image(fileitem, target_path, url) - mock_request_utils.assert_called_with( + mock_instance.stream.assert_called_with( + url, proxies=self.media_chain.runtime_config.proxy, ua=self.media_chain.runtime_config.normal_user_agent, ) - mock_instance.get_stream.assert_called_with(url=url) mock_temp_file.assert_called_once_with(delete=False, suffix=".jpg") tmp_mock.write.assert_any_call(b"data1") tmp_mock.write.assert_any_call(b"data2") diff --git a/tests/test_music_scrape.py b/tests/test_music_scrape.py index 8fa0a6bae..aa9567617 100644 --- a/tests/test_music_scrape.py +++ b/tests/test_music_scrape.py @@ -1,6 +1,7 @@ from types import SimpleNamespace from unittest.mock import Mock, patch +from app.application.configuration import get_chain_runtime_config_snapshot from app.chain.scraping import ScrapingChain, ScrapingConfig, _MusicScrapeFileResult from app.domain.context import MUSIC_ENTITY_ALBUM, MusicAlbumInfo, MusicInfo, MusicLyrics from app.runtime.events import Event @@ -120,12 +121,18 @@ def test_music_cover_download_uses_bounded_external_response_cache() -> None: request.get_res.return_value = response ScrapingChain._request_music_cover.cache_clear() - with patch("app.startup.initializers.network.RequestUtils", return_value=request): + with patch("app.chain.scraping._scraping_http_snapshot") as snapshot: + snapshot.return_value.get.return_value = response first = ScrapingChain._download_music_cover("https://example.com/album.webp") second = ScrapingChain._download_music_cover("https://example.com/album.webp") assert first == second == (b"cover", "image/webp") - request.get_res.assert_called_once_with("https://example.com/album.webp") + snapshot.return_value.get.assert_called_once_with( + "https://example.com/album.webp", + proxies=None, + ua=get_chain_runtime_config_snapshot().normal_user_agent, + timeout=20, + ) response.close.assert_called_once() ScrapingChain._request_music_cover.cache_clear() diff --git a/tests/test_plugin_backup_restore.py b/tests/test_plugin_backup_restore.py index 4c79a02f7..2e36f9b86 100644 --- a/tests/test_plugin_backup_restore.py +++ b/tests/test_plugin_backup_restore.py @@ -8,7 +8,7 @@ from app.adapters.system.plugin import package as package_module from app.adapters.system.plugin.package import PluginPackageManager from app.chain import system as system_module from app.chain.system import SystemChain -from app.startup.initializers import network as network_initializer +from app.adapters.system.host import SystemUtils def _patch_docker_paths(monkeypatch, tmp_path: Path, *, reset: bool) -> Path: @@ -28,7 +28,7 @@ def _patch_docker_paths(monkeypatch, tmp_path: Path, *, reset: bool) -> Path: lambda: runtime_config, ) monkeypatch.setattr( - network_initializer.SystemUtils, + SystemUtils, "is_docker", staticmethod(lambda: True), ) diff --git a/tests/test_residual_provider_resets.py b/tests/test_residual_provider_resets.py index 4b58bac83..069b15d85 100644 --- a/tests/test_residual_provider_resets.py +++ b/tests/test_residual_provider_resets.py @@ -27,7 +27,7 @@ from app.runtime.resources import ( ) from app.scheduler.facade import Scheduler from app.schemas.types import EventType -from app.startup.initializers import resources as managed_resource_initializer +from app.startup.composition import resource as managed_resource_composition _MISSING = object() @@ -186,12 +186,12 @@ def test_managed_resource_owner_reset_releases_only_closed_runtime( """托管资源 reset 只释放已关闭引用,不把释放动作伪装为完整重启。""" first = SimpleNamespace(is_shutdown=True) second = SimpleNamespace(is_shutdown=True) - monkeypatch.setattr(managed_resource_initializer, "_managed_resource_runtime", first) + monkeypatch.setattr(managed_resource_composition, "_managed_resource_runtime", first) monkeypatch.setattr(managed_resource_facade, "_managed_resource_runtime", first) - managed_resource_initializer.reset_managed_resources() - managed_resource_initializer.reset_managed_resources() - assert managed_resource_initializer._managed_resource_runtime is None + managed_resource_composition.reset_managed_resource_composition() + managed_resource_composition.reset_managed_resource_composition() + assert managed_resource_composition._managed_resource_runtime is None assert managed_resource_facade._managed_resource_runtime is None configure_managed_resource_runtime(second) # type: ignore[arg-type] @@ -205,11 +205,11 @@ def test_managed_resource_owner_refuses_to_release_live_runtime( ) -> None: """托管资源仍活动时 reset 必须保留 owner,避免隐藏未收口资源。""" runtime = SimpleNamespace(is_shutdown=False) - monkeypatch.setattr(managed_resource_initializer, "_managed_resource_runtime", runtime) + monkeypatch.setattr(managed_resource_composition, "_managed_resource_runtime", runtime) monkeypatch.setattr(managed_resource_facade, "_managed_resource_runtime", runtime) with pytest.raises(RuntimeError, match="尚未关闭"): - managed_resource_initializer.reset_managed_resources() + managed_resource_composition.reset_managed_resource_composition() - assert managed_resource_initializer._managed_resource_runtime is runtime + assert managed_resource_composition._managed_resource_runtime is runtime assert managed_resource_facade._managed_resource_runtime is runtime diff --git a/tests/test_resource_v3.py b/tests/test_resource_v3.py index 1463bc00f..beba8e76f 100644 --- a/tests/test_resource_v3.py +++ b/tests/test_resource_v3.py @@ -2,14 +2,14 @@ from pathlib import Path import pytest -from app.runtime.config import settings from app.adapters.system.resource import ( ResourceHelper, configure_resource_version_provider, ) +from app.runtime.config import settings +from app.startup.composition import resource as resource_composition from app.startup.initializers import modules as modules_initializer - ROOT_DIR = Path(__file__).resolve().parents[1] @@ -75,7 +75,7 @@ def test_startup_owns_restart_after_resource_update(monkeypatch): """资源适配器只返回更新结果,进程重启必须由启动组合层触发。""" restart_calls = [] monkeypatch.setattr( - modules_initializer, + resource_composition, "ResourceHelper", lambda: type( "ResourceStub", @@ -97,7 +97,7 @@ def test_startup_owns_restart_after_resource_update(monkeypatch): def test_startup_does_not_restart_without_resource_update(monkeypatch): """没有成功安装新资源时启动层不得请求重启。""" monkeypatch.setattr( - modules_initializer, + resource_composition, "ResourceHelper", lambda: type( "ResourceStub", diff --git a/tests/test_runtime_composition.py b/tests/test_runtime_composition.py index 973afa1ba..24446ce1f 100644 --- a/tests/test_runtime_composition.py +++ b/tests/test_runtime_composition.py @@ -27,6 +27,7 @@ def _inputs() -> runtime_composition.RuntimeInputs: system_config = Mock(name="system_config") configuration = SimpleNamespace( system_config=system_config, + system_service=Mock(name="system_service"), runtime=Mock(name="runtime_configuration"), settings=Mock(name="runtime_settings"), ) @@ -77,6 +78,7 @@ def test_runtime_composition_reuses_dependencies_and_projects_api_identity() -> assert runtime.authentication.passkey_repository is inputs.authentication.passkey_repository assert runtime.configuration is inputs.configuration.runtime assert runtime.settings is inputs.configuration.settings + assert runtime.system._system_config is inputs.configuration.system_service assert runtime.tasks is inputs.tasks assert runtime.messaging.helper is inputs.dependencies.message_helper assert runtime.messaging.queue is inputs.dependencies.message_queue diff --git a/tests/test_sunnypt_indexer.py b/tests/test_sunnypt_indexer.py index 9490cc7d1..1aa12a1b9 100644 --- a/tests/test_sunnypt_indexer.py +++ b/tests/test_sunnypt_indexer.py @@ -470,7 +470,7 @@ def test_indirect_download_does_not_log_or_cache_temporary_url(monkeypatch): log_messages.append(message) monkeypatch.setattr( - "app.startup.initializers.network.RequestUtils.post_res", + "app.adapters.network.http.RequestUtils.post_res", fake_post_res, ) monkeypatch.setattr( diff --git a/tests/test_yemapt_open_api.py b/tests/test_yemapt_open_api.py index 49155df0a..ceea0bd86 100644 --- a/tests/test_yemapt_open_api.py +++ b/tests/test_yemapt_open_api.py @@ -332,7 +332,7 @@ def test_yemapt_download_generates_and_urlencodes_temporary_key(monkeypatch): return None, b"torrent-content", "Movie", ["Movie.mkv"], "" monkeypatch.setattr( - "app.startup.initializers.network.RequestUtils.post_res", + "app.adapters.network.http.RequestUtils.post_res", fake_post_res, ) monkeypatch.setattr(