From 0afc5e2349cc97c54550837cf14345b97c5d0d09 Mon Sep 17 00:00:00 2001 From: jxxghp Date: Wed, 16 Sep 2026 07:01:10 +0800 Subject: [PATCH] =?UTF-8?q?fix(architecture):=20=E5=90=8C=E6=AD=A5?= =?UTF-8?q?=E6=A8=A1=E5=9D=97=E8=BF=81=E7=A7=BB=E9=97=A8=E7=A6=81=E5=BC=95?= =?UTF-8?q?=E7=94=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/architecture-overview.md | 4 +- docs/refactor/optimization-checklist.md | 2 +- docs/rules/05-architecture.md | 2 +- .../architecture/dependency-baseline.json | 248 +++++++++++++----- .../architecture/filename-policy.json | 10 + tests/test_acceleration.py | 14 +- tests/test_lifecycle_provider_resets.py | 4 +- ...ansfer_failure_notification_aggregation.py | 4 +- tests/test_transfer_history_legacy_compat.py | 2 +- 9 files changed, 205 insertions(+), 85 deletions(-) diff --git a/docs/architecture-overview.md b/docs/architecture-overview.md index c4cbcc6f2..43f71da06 100644 --- a/docs/architecture-overview.md +++ b/docs/architecture-overview.md @@ -453,7 +453,7 @@ flowchart LR ``` - Oper 只接收和返回持久化值;`MediaInfo` / `MetaBase` 与数据库行之间的转换属于业务逻辑, - 归 `app/application/`(见 `application/subscription/write.py`、`application/history.py`)。 + 归 `app/application/`(见 `application/subscription/write.py`、`application/history/`)。 订阅新增、查询、变更、删除、身份和搜索契约已经统一收口在 `application/subscription/`, 不再保留主题包之外的第二个写入入口。 - 规范写入口中的 Oper 只 stage mutation,不创建独立 Session、不提交;Application Command @@ -761,7 +761,7 @@ flowchart LR | 指标 | 当前值 | |---|---:| | Python 模块 | 1025 | -| 内部导入边 | 8,733 | +| 内部导入边 | 8,829 | | 非平凡 SCC | 1(精确 containment 的 TMDB 移植包环) | | Application / Chain 具体 Adapter 直连 | 0 / 0 | | Direct egress | 53(债务已清零,53 条精确 containment) | diff --git a/docs/refactor/optimization-checklist.md b/docs/refactor/optimization-checklist.md index fc9b2cab8..3454672d3 100644 --- a/docs/refactor/optimization-checklist.md +++ b/docs/refactor/optimization-checklist.md @@ -94,7 +94,7 @@ ARCH-201 至 ARCH-204 均达到实现、验证、提交、推送和远端门禁 | 指标 | 当前值 | 解释 | |---|---:|---| -| 宿主 Python 模块 / 内部依赖边 | 1025 / 8,733 | `dependency-baseline.json` 当前快照;系统设置合同按 `app.application.settings` 包组织,系统设置 API 端点独立按 `app.api.endpoints.settings` 归档,分类、下载资源归类、订阅搜索、整理恢复、Agent 计划、工具视觉、终端生命周期与终端作用域模块的受控依赖 | +| 宿主 Python 模块 / 内部依赖边 | 1039 / 8,829 | `dependency-baseline.json` 当前快照;系统设置合同按 `app.application.settings` 包组织,系统设置 API 端点独立按 `app.api.endpoints.settings` 归档,分类、下载资源归类、订阅搜索、整理恢复、Agent 计划、工具视觉、终端生命周期与终端作用域模块的受控依赖 | | 非平凡 SCC | 1 | 仅保留精确 containment 的 29 模块 TMDB 移植包环 | | 跨层 DB 边界债务 | 0 | Application、Chain、API、Agent、Runtime、Workflow 到 DB 的受控债务均为零 | | Model/Oper 事务债务 | 0 | 自建 Session、自动事务装饰器、直接 commit/rollback 等基线均为零 | diff --git a/docs/rules/05-architecture.md b/docs/rules/05-architecture.md index 5d65c0afd..025a1ee2e 100644 --- a/docs/rules/05-architecture.md +++ b/docs/rules/05-architecture.md @@ -814,7 +814,7 @@ mechanics. Every schema change requires an Alembic migration under Oper classes take and return persistence values, not domain objects. Translating `MediaInfo` / `MetaBase` into a row is business logic and belongs in -`app/application/` — see `application/subscription/write.py` and `application/history.py` +`app/application/` — see `application/subscription/write.py` and `application/history/` for the two write paths. Column-type coercion (numeric year to string, boolean switches to integers) stays in the Oper because it follows the column, not the caller. diff --git a/tests/fixtures/architecture/dependency-baseline.json b/tests/fixtures/architecture/dependency-baseline.json index 05d3afd79..c04e8b0e7 100644 --- a/tests/fixtures/architecture/dependency-baseline.json +++ b/tests/fixtures/architecture/dependency-baseline.json @@ -6,8 +6,8 @@ "api_endpoints_to_sessions": [], "api_to_db": [], "application_to_agent": [ - "app.application.messaging.webagentstream -> app.agent", - "app.application.messaging.webagentstream -> app.agent.steering" + "app.application.messaging.webagent.stream -> app.agent", + "app.application.messaging.webagent.stream -> app.agent.steering" ], "application_to_db": [], "chain_to_db": [], @@ -1077,8 +1077,8 @@ "runtime_only": true } }, - "edge_count": 8733, - "edge_sha256": "cd429302ed1a133cca47d34cf95a419474398422590d987e95f5a72a83cdaefd", + "edge_count": 8829, + "edge_sha256": "1c9a0e908924988746ee43009c931bd43c3df419ce4de07f663d564626d89f60", "edges": [ "app -> app.foundation", "app -> app.foundation.environment", @@ -1749,7 +1749,8 @@ "app.agent.tools.base -> app.application", "app.agent.tools.base -> app.application.agent", "app.agent.tools.base -> app.application.messaging", - "app.agent.tools.base -> app.application.messaging.agent", + "app.agent.tools.base -> app.application.messaging.channel", + "app.agent.tools.base -> app.application.messaging.channel.admin", "app.agent.tools.base -> app.application.notification", "app.agent.tools.base -> app.chain", "app.agent.tools.base -> app.chain.base", @@ -1838,7 +1839,8 @@ "app.agent.tools.impl.ask_user_choice -> app.agent.tools.tags", "app.agent.tools.impl.ask_user_choice -> app.application", "app.agent.tools.impl.ask_user_choice -> app.application.messaging", - "app.agent.tools.impl.ask_user_choice -> app.application.messaging.agent", + "app.agent.tools.impl.ask_user_choice -> app.application.messaging.interaction", + "app.agent.tools.impl.ask_user_choice -> app.application.messaging.interaction.agent", "app.agent.tools.impl.ask_user_choice -> app.runtime", "app.agent.tools.impl.ask_user_choice -> app.runtime.log", "app.agent.tools.impl.ask_user_choice -> app.schemas", @@ -2065,6 +2067,7 @@ "app.api.dependencies.history -> app.application", "app.api.dependencies.history -> app.application.dashboard", "app.api.dependencies.history -> app.application.history", + "app.api.dependencies.history -> app.application.history.retry", "app.api.dependencies.history -> app.application.mediaserver", "app.api.dependencies.history -> app.application.transfer", "app.api.dependencies.history -> app.application.transfer.execution", @@ -2174,6 +2177,8 @@ "app.api.endpoints.agent -> app.application.messaging", "app.api.endpoints.agent -> app.application.messaging.agent", "app.api.endpoints.agent -> app.application.messaging.chat", + "app.api.endpoints.agent -> app.application.messaging.interaction", + "app.api.endpoints.agent -> app.application.messaging.interaction.agent", "app.api.endpoints.agent -> app.runtime", "app.api.endpoints.agent -> app.runtime.events", "app.api.endpoints.agent -> app.runtime.localization", @@ -3330,6 +3335,7 @@ "app.application.classification.contract -> app.schemas.category", "app.application.classification.enrichment -> app.domain", "app.application.classification.enrichment -> app.domain.classification", + "app.application.classification.enrichment -> app.domain.classification.conditions", "app.application.classification.enrichment -> app.domain.classification.evaluator", "app.application.classification.enrichment -> app.domain.classification.fields", "app.application.classification.enrichment -> app.schemas", @@ -3354,6 +3360,7 @@ "app.application.classification.migration -> app.application.classification.compiler", "app.application.classification.migration -> app.domain", "app.application.classification.migration -> app.domain.classification", + "app.application.classification.migration -> app.domain.classification.conditions", "app.application.classification.migration -> app.domain.classification.vocabulary", "app.application.classification.migration -> app.schemas", "app.application.classification.migration -> app.schemas.category", @@ -3362,6 +3369,7 @@ "app.application.classification.projection -> app.application.classification.migration", "app.application.classification.projection -> app.domain", "app.application.classification.projection -> app.domain.classification", + "app.application.classification.projection -> app.domain.classification.conditions", "app.application.classification.projection -> app.domain.classification.vocabulary", "app.application.classification.projection -> app.schemas", "app.application.classification.projection -> app.schemas.category", @@ -3407,6 +3415,8 @@ "app.application.download.classification -> app.application.classification", "app.application.download.classification -> app.application.classification.reference", "app.application.download.classification -> app.application.directory", + "app.application.download.classification -> app.application.download", + "app.application.download.classification -> app.application.download.validation", "app.application.download.classification -> app.application.history", "app.application.download.classification -> app.domain", "app.application.download.classification -> app.domain.classification", @@ -3420,6 +3430,8 @@ "app.application.download.organization -> app.application", "app.application.download.organization -> app.application.configuration", "app.application.download.organization -> app.application.directory", + "app.application.download.organization -> app.application.download", + "app.application.download.organization -> app.application.download.validation", "app.application.download.organization -> app.domain", "app.application.download.organization -> app.domain.classification", "app.application.download.organization -> app.domain.classification.validation", @@ -3436,6 +3448,8 @@ "app.application.download.selection -> app.schemas.mediaserver", "app.application.download.tasks -> app.application", "app.application.download.tasks -> app.application.directory", + "app.application.download.tasks -> app.application.download", + "app.application.download.tasks -> app.application.download.validation", "app.application.download.tasks -> app.application.history", "app.application.download.tasks -> app.schemas", "app.application.download.tasks -> app.schemas.transfer", @@ -3466,8 +3480,8 @@ "app.application.formatting -> app.schemas.transfer", "app.application.formatting -> app.schemas.workflow", "app.application.history -> app.application", - "app.application.history -> app.application.configuration", - "app.application.history -> app.application.historymutation", + "app.application.history -> app.application.history.contracts", + "app.application.history -> app.application.history.mutation", "app.application.history -> app.application.transfer", "app.application.history -> app.application.transfer.history", "app.application.history -> app.domain", @@ -3476,22 +3490,29 @@ "app.application.history -> app.domain.meta.metabase", "app.application.history -> app.foundation", "app.application.history -> app.foundation.text", - "app.application.history -> app.runtime", - "app.application.history -> app.runtime.cache", - "app.application.history -> app.runtime.log", "app.application.history -> app.schemas", "app.application.history -> app.schemas.common", "app.application.history -> app.schemas.file", "app.application.history -> app.schemas.history", "app.application.history -> app.schemas.transfer", "app.application.history -> app.schemas.types", - "app.application.historymutation -> app.application", - "app.application.historymutation -> app.application.transfer", - "app.application.historymutation -> app.application.transfer.execution", - "app.application.historymutation -> app.application.transfer.recovery", - "app.application.historymutation -> app.schemas", - "app.application.historymutation -> app.schemas.common", - "app.application.historymutation -> app.schemas.history", + "app.application.history.contracts -> app.schemas", + "app.application.history.contracts -> app.schemas.common", + "app.application.history.contracts -> app.schemas.types", + "app.application.history.mutation -> app.application", + "app.application.history.mutation -> app.application.transfer", + "app.application.history.mutation -> app.application.transfer.execution", + "app.application.history.mutation -> app.application.transfer.recovery", + "app.application.history.mutation -> app.schemas", + "app.application.history.mutation -> app.schemas.common", + "app.application.history.mutation -> app.schemas.history", + "app.application.history.retry -> app.application", + "app.application.history.retry -> app.application.configuration", + "app.application.history.retry -> app.application.history", + "app.application.history.retry -> app.application.history.contracts", + "app.application.history.retry -> app.runtime", + "app.application.history.retry -> app.runtime.cache", + "app.application.history.retry -> app.runtime.log", "app.application.image -> app.application", "app.application.image -> app.application.configuration", "app.application.image -> app.application.security", @@ -3522,8 +3543,12 @@ "app.application.messaging.agent -> app.application.configuration", "app.application.messaging.agent -> app.application.messaging", "app.application.messaging.agent -> app.application.messaging.chat", + "app.application.messaging.agent -> app.application.messaging.interaction", + "app.application.messaging.agent -> app.application.messaging.interaction.agent", "app.application.messaging.agent -> app.application.messaging.router", - "app.application.messaging.agent -> app.application.messaging.webagentstream", + "app.application.messaging.agent -> app.application.messaging.webagent", + "app.application.messaging.agent -> app.application.messaging.webagent.events", + "app.application.messaging.agent -> app.application.messaging.webagent.stream", "app.application.messaging.agent -> app.runtime", "app.application.messaging.agent -> app.runtime.execution", "app.application.messaging.agent -> app.runtime.log", @@ -3531,6 +3556,8 @@ "app.application.messaging.agent -> app.schemas", "app.application.messaging.agent -> app.schemas.message", "app.application.messaging.agent -> app.schemas.types", + "app.application.messaging.channel.admin -> app.schemas", + "app.application.messaging.channel.admin -> app.schemas.types", "app.application.messaging.chat -> app.application", "app.application.messaging.chat -> app.application.database", "app.application.messaging.chat -> app.runtime", @@ -3545,6 +3572,9 @@ "app.application.messaging.interaction -> app.schemas.message", "app.application.messaging.interaction -> app.schemas.notification", "app.application.messaging.interaction -> app.schemas.types", + "app.application.messaging.media -> app.application", + "app.application.messaging.media -> app.application.messaging", + "app.application.messaging.media -> app.application.messaging.interaction", "app.application.messaging.media -> app.domain", "app.application.messaging.media -> app.domain.context", "app.application.messaging.media -> app.domain.meta", @@ -3623,16 +3653,21 @@ "app.application.messaging.update -> app.schemas.notification", "app.application.messaging.update -> app.schemas.system", "app.application.messaging.update -> app.schemas.types", - "app.application.messaging.webagentstream -> app.agent", - "app.application.messaging.webagentstream -> app.agent.steering", - "app.application.messaging.webagentstream -> app.application", - "app.application.messaging.webagentstream -> app.application.agent", - "app.application.messaging.webagentstream -> app.runtime", - "app.application.messaging.webagentstream -> app.runtime.log", - "app.application.messaging.webagentstream -> app.runtime.stop", - "app.application.messaging.webagentstream -> app.schemas", - "app.application.messaging.webagentstream -> app.schemas.message", - "app.application.messaging.webagentstream -> app.schemas.types", + "app.application.messaging.webagent.events -> app.runtime", + "app.application.messaging.webagent.events -> app.runtime.log", + "app.application.messaging.webagent.events -> app.schemas", + "app.application.messaging.webagent.events -> app.schemas.message", + "app.application.messaging.webagent.events -> app.schemas.types", + "app.application.messaging.webagent.stream -> app.agent", + "app.application.messaging.webagent.stream -> app.agent.steering", + "app.application.messaging.webagent.stream -> app.application", + "app.application.messaging.webagent.stream -> app.application.agent", + "app.application.messaging.webagent.stream -> app.runtime", + "app.application.messaging.webagent.stream -> app.runtime.log", + "app.application.messaging.webagent.stream -> app.runtime.stop", + "app.application.messaging.webagent.stream -> app.schemas", + "app.application.messaging.webagent.stream -> app.schemas.message", + "app.application.messaging.webagent.stream -> app.schemas.types", "app.application.music.catalog -> app.domain", "app.application.music.catalog -> app.domain.context", "app.application.music.catalog -> app.domain.meta", @@ -3836,12 +3871,15 @@ "app.application.security.userconfig -> app.schemas.types", "app.application.servarr -> app.schemas", "app.application.servarr -> app.schemas.types", - "app.application.server.report -> app.schemas", - "app.application.server.report -> app.schemas.media", + "app.application.server.payload -> app.schemas", + "app.application.server.payload -> app.schemas.media", + "app.application.server.report -> app.application", + "app.application.server.report -> app.application.server", + "app.application.server.report -> app.application.server.payload", "app.application.server.share -> app.application", + "app.application.server.share -> app.application.server", + "app.application.server.share -> app.application.server.payload", "app.application.server.share -> app.application.workflow", - "app.application.server.share -> app.schemas", - "app.application.server.share -> app.schemas.media", "app.application.service -> app.schemas", "app.application.service -> app.schemas.system", "app.application.service -> app.schemas.types", @@ -4077,34 +4115,67 @@ "app.application.transfer.history -> app.schemas.media", "app.application.transfer.history -> app.schemas.transfer", "app.application.transfer.history -> app.schemas.types", + "app.application.transfer.jobs -> app.application", + "app.application.transfer.jobs -> app.application.transfer", + "app.application.transfer.jobs -> app.application.transfer.projection", + "app.application.transfer.jobs -> app.domain", + "app.application.transfer.jobs -> app.domain.context", + "app.application.transfer.jobs -> app.domain.media", + "app.application.transfer.jobs -> app.domain.meta", + "app.application.transfer.jobs -> app.domain.meta.metabase", + "app.application.transfer.jobs -> app.domain.meta.metamusic", + "app.application.transfer.jobs -> app.foundation", + "app.application.transfer.jobs -> app.foundation.text", + "app.application.transfer.jobs -> app.runtime", + "app.application.transfer.jobs -> app.runtime.log", + "app.application.transfer.jobs -> app.schemas", + "app.application.transfer.jobs -> app.schemas.context", + "app.application.transfer.jobs -> app.schemas.file", + "app.application.transfer.jobs -> app.schemas.media", + "app.application.transfer.jobs -> app.schemas.music", + "app.application.transfer.jobs -> app.schemas.transfer", + "app.application.transfer.jobs -> app.schemas.types", + "app.application.transfer.models -> app.application", + "app.application.transfer.models -> app.application.history", + "app.application.transfer.models -> app.application.transfer", + "app.application.transfer.models -> app.application.transfer.checkpoint", + "app.application.transfer.models -> app.application.transfer.execution", + "app.application.transfer.models -> app.application.transfer.projection", + "app.application.transfer.models -> app.domain", + "app.application.transfer.models -> app.domain.context", + "app.application.transfer.models -> app.domain.meta", + "app.application.transfer.models -> app.domain.meta.metabase", + "app.application.transfer.models -> app.domain.meta.metamusic", + "app.application.transfer.models -> app.schemas", + "app.application.transfer.models -> app.schemas.file", + "app.application.transfer.models -> app.schemas.media", + "app.application.transfer.models -> app.schemas.system", + "app.application.transfer.models -> app.schemas.tmdb", + "app.application.transfer.models -> app.schemas.transfer", + "app.application.transfer.models -> app.schemas.types", + "app.application.transfer.notifications -> app.application", + "app.application.transfer.notifications -> app.application.transfer", + "app.application.transfer.notifications -> app.application.transfer.feedback", + "app.application.transfer.notifications -> app.runtime", + "app.application.transfer.notifications -> app.runtime.log", + "app.application.transfer.notifications -> app.schemas", + "app.application.transfer.notifications -> app.schemas.media", + "app.application.transfer.projection -> app.domain", + "app.application.transfer.projection -> app.domain.meta", + "app.application.transfer.projection -> app.domain.meta.metabase", "app.application.transfer.recovery -> app.application", "app.application.transfer.recovery -> app.application.transfer", "app.application.transfer.recovery -> app.application.transfer.execution", "app.application.transfer.workflow -> app.application", - "app.application.transfer.workflow -> app.application.history", "app.application.transfer.workflow -> app.application.transfer", - "app.application.transfer.workflow -> app.application.transfer.checkpoint", - "app.application.transfer.workflow -> app.application.transfer.execution", "app.application.transfer.workflow -> app.application.transfer.feedback", - "app.application.transfer.workflow -> app.domain", - "app.application.transfer.workflow -> app.domain.context", - "app.application.transfer.workflow -> app.domain.media", - "app.application.transfer.workflow -> app.domain.meta", - "app.application.transfer.workflow -> app.domain.meta.metabase", - "app.application.transfer.workflow -> app.domain.meta.metamusic", - "app.application.transfer.workflow -> app.foundation", - "app.application.transfer.workflow -> app.foundation.text", - "app.application.transfer.workflow -> app.runtime", - "app.application.transfer.workflow -> app.runtime.log", + "app.application.transfer.workflow -> app.application.transfer.jobs", + "app.application.transfer.workflow -> app.application.transfer.models", + "app.application.transfer.workflow -> app.application.transfer.notifications", + "app.application.transfer.workflow -> app.application.transfer.projection", "app.application.transfer.workflow -> app.schemas", - "app.application.transfer.workflow -> app.schemas.context", "app.application.transfer.workflow -> app.schemas.file", - "app.application.transfer.workflow -> app.schemas.media", - "app.application.transfer.workflow -> app.schemas.music", - "app.application.transfer.workflow -> app.schemas.system", - "app.application.transfer.workflow -> app.schemas.tmdb", "app.application.transfer.workflow -> app.schemas.transfer", - "app.application.transfer.workflow -> app.schemas.types", "app.application.workflow -> app.schemas", "app.application.workflow -> app.schemas.common", "app.chain._interaction -> app.chain", @@ -4113,8 +4184,9 @@ "app.chain._interaction -> app.schemas.types", "app.chain._messaging -> app.application", "app.chain._messaging -> app.application.messaging", - "app.chain._messaging -> app.application.messaging.agent", "app.chain._messaging -> app.application.messaging.message", + "app.chain._messaging -> app.application.messaging.webagent", + "app.chain._messaging -> app.application.messaging.webagent.events", "app.chain._messaging -> app.application.notification", "app.chain._messaging -> app.application.security", "app.chain._messaging -> app.application.security.user", @@ -4640,8 +4712,8 @@ "app.chain.message -> app.application", "app.chain.message -> app.application.agent", "app.chain.message -> app.application.messaging", - "app.chain.message -> app.application.messaging.agent", "app.chain.message -> app.application.messaging.interaction", + "app.chain.message -> app.application.messaging.interaction.agent", "app.chain.message -> app.application.messaging.media", "app.chain.message -> app.application.messaging.plugin", "app.chain.message -> app.application.messaging.router", @@ -5302,6 +5374,7 @@ "app.chain.transfer.execution -> app.application", "app.chain.transfer.execution -> app.application.directory", "app.chain.transfer.execution -> app.application.history", + "app.chain.transfer.execution -> app.application.history.retry", "app.chain.transfer.execution -> app.application.transfer", "app.chain.transfer.execution -> app.application.transfer.execution", "app.chain.transfer.execution -> app.application.transfer.workflow", @@ -5347,6 +5420,7 @@ "app.chain.transfer.filter -> app.application.configuration", "app.chain.transfer.filter -> app.application.directory", "app.chain.transfer.filter -> app.application.history", + "app.chain.transfer.filter -> app.application.history.retry", "app.chain.transfer.filter -> app.application.transfer", "app.chain.transfer.filter -> app.application.transfer.workflow", "app.chain.transfer.filter -> app.chain", @@ -5371,6 +5445,7 @@ "app.chain.transfer.format -> app.application.configuration", "app.chain.transfer.format -> app.application.formatting", "app.chain.transfer.format -> app.application.history", + "app.chain.transfer.format -> app.application.history.retry", "app.chain.transfer.format -> app.application.transfer", "app.chain.transfer.format -> app.application.transfer.feedback", "app.chain.transfer.format -> app.application.transfer.workflow", @@ -5462,6 +5537,7 @@ "app.chain.transfer.records -> app.application.classification", "app.chain.transfer.records -> app.application.classification.reference", "app.chain.transfer.records -> app.application.history", + "app.chain.transfer.records -> app.application.history.retry", "app.chain.transfer.records -> app.application.transfer", "app.chain.transfer.records -> app.application.transfer.execution", "app.chain.transfer.records -> app.application.transfer.recovery", @@ -5541,6 +5617,7 @@ "app.chain.transfer.settlement -> app.application.chain.events", "app.chain.transfer.settlement -> app.application.configuration", "app.chain.transfer.settlement -> app.application.history", + "app.chain.transfer.settlement -> app.application.history.retry", "app.chain.transfer.settlement -> app.application.outbox", "app.chain.transfer.settlement -> app.application.transfer", "app.chain.transfer.settlement -> app.application.transfer.execution", @@ -5571,6 +5648,7 @@ "app.chain.transfer.workflow -> app.application.directory", "app.chain.transfer.workflow -> app.application.formatting", "app.chain.transfer.workflow -> app.application.history", + "app.chain.transfer.workflow -> app.application.history.retry", "app.chain.transfer.workflow -> app.application.transfer", "app.chain.transfer.workflow -> app.application.transfer.history", "app.chain.transfer.workflow -> app.application.transfer.workflow", @@ -5739,6 +5817,7 @@ "app.db.adapters.history.download -> app.schemas.types", "app.db.adapters.history.transfer -> app.application", "app.db.adapters.history.transfer -> app.application.history", + "app.db.adapters.history.transfer -> app.application.history.retry", "app.db.adapters.history.transfer -> app.application.transfer", "app.db.adapters.history.transfer -> app.application.transfer.feedback", "app.db.adapters.history.transfer -> app.db", @@ -6214,6 +6293,8 @@ "app.doctor.runner -> app.runtime", "app.doctor.runner -> app.runtime.settings", "app.doctor.runner -> app.runtime.version", + "app.domain.classification.conditions -> app.schemas", + "app.domain.classification.conditions -> app.schemas.category", "app.domain.classification.evaluator -> app.schemas", "app.domain.classification.evaluator -> app.schemas.category", "app.domain.classification.facts -> app.domain", @@ -6447,7 +6528,8 @@ "app.modules._base.mediaserver -> app.schemas.types", "app.modules._base.notification -> app.application", "app.modules._base.notification -> app.application.messaging", - "app.modules._base.notification -> app.application.messaging.agent", + "app.modules._base.notification -> app.application.messaging.channel", + "app.modules._base.notification -> app.application.messaging.channel.admin", "app.modules._base.notification -> app.foundation", "app.modules._base.notification -> app.foundation.collections", "app.modules._base.notification -> app.modules", @@ -6562,7 +6644,8 @@ "app.modules.discord -> app.adapters.network.http", "app.modules.discord -> app.application", "app.modules.discord -> app.application.messaging", - "app.modules.discord -> app.application.messaging.agent", + "app.modules.discord -> app.application.messaging.channel", + "app.modules.discord -> app.application.messaging.channel.admin", "app.modules.discord -> app.domain", "app.modules.discord -> app.domain.context", "app.modules.discord -> app.modules", @@ -6670,7 +6753,8 @@ "app.modules.fanart -> app.schemas.types", "app.modules.feishu -> app.application", "app.modules.feishu -> app.application.messaging", - "app.modules.feishu -> app.application.messaging.agent", + "app.modules.feishu -> app.application.messaging.channel", + "app.modules.feishu -> app.application.messaging.channel.admin", "app.modules.feishu -> app.domain", "app.modules.feishu -> app.domain.context", "app.modules.feishu -> app.modules", @@ -6688,7 +6772,8 @@ "app.modules.feishu.feishu -> app.adapters.network.http", "app.modules.feishu.feishu -> app.application", "app.modules.feishu.feishu -> app.application.messaging", - "app.modules.feishu.feishu -> app.application.messaging.agent", + "app.modules.feishu.feishu -> app.application.messaging.channel", + "app.modules.feishu.feishu -> app.application.messaging.channel.admin", "app.modules.feishu.feishu -> app.application.messaging.ingress", "app.modules.feishu.feishu -> app.application.security", "app.modules.feishu.feishu -> app.application.security.user", @@ -7456,7 +7541,8 @@ "app.modules.qqbot.module -> app.adapters.network.http", "app.modules.qqbot.module -> app.application", "app.modules.qqbot.module -> app.application.messaging", - "app.modules.qqbot.module -> app.application.messaging.agent", + "app.modules.qqbot.module -> app.application.messaging.channel", + "app.modules.qqbot.module -> app.application.messaging.channel.admin", "app.modules.qqbot.module -> app.domain", "app.modules.qqbot.module -> app.domain.context", "app.modules.qqbot.module -> app.modules", @@ -7518,7 +7604,8 @@ "app.modules.rtorrent.rtorrent -> app.runtime.log", "app.modules.slack -> app.application", "app.modules.slack -> app.application.messaging", - "app.modules.slack -> app.application.messaging.agent", + "app.modules.slack -> app.application.messaging.channel", + "app.modules.slack -> app.application.messaging.channel.admin", "app.modules.slack -> app.domain", "app.modules.slack -> app.domain.context", "app.modules.slack -> app.modules", @@ -7565,7 +7652,8 @@ "app.modules.synologychat -> app.adapters.network.http", "app.modules.synologychat -> app.application", "app.modules.synologychat -> app.application.messaging", - "app.modules.synologychat -> app.application.messaging.agent", + "app.modules.synologychat -> app.application.messaging.channel", + "app.modules.synologychat -> app.application.messaging.channel.admin", "app.modules.synologychat -> app.domain", "app.modules.synologychat -> app.domain.context", "app.modules.synologychat -> app.modules", @@ -7591,7 +7679,8 @@ "app.modules.synologychat.synologychat -> app.runtime.log", "app.modules.telegram.module -> app.application", "app.modules.telegram.module -> app.application.messaging", - "app.modules.telegram.module -> app.application.messaging.agent", + "app.modules.telegram.module -> app.application.messaging.channel", + "app.modules.telegram.module -> app.application.messaging.channel.admin", "app.modules.telegram.module -> app.domain", "app.modules.telegram.module -> app.domain.context", "app.modules.telegram.module -> app.modules", @@ -7971,7 +8060,8 @@ "app.modules.ugreen.ugreen -> app.schemas.types", "app.modules.vocechat -> app.application", "app.modules.vocechat -> app.application.messaging", - "app.modules.vocechat -> app.application.messaging.agent", + "app.modules.vocechat -> app.application.messaging.channel", + "app.modules.vocechat -> app.application.messaging.channel.admin", "app.modules.vocechat -> app.domain", "app.modules.vocechat -> app.domain.context", "app.modules.vocechat -> app.modules", @@ -8008,7 +8098,8 @@ "app.modules.wechat -> app.adapters.external.wechat", "app.modules.wechat -> app.application", "app.modules.wechat -> app.application.messaging", - "app.modules.wechat -> app.application.messaging.agent", + "app.modules.wechat -> app.application.messaging.channel", + "app.modules.wechat -> app.application.messaging.channel.admin", "app.modules.wechat -> app.domain", "app.modules.wechat -> app.domain.context", "app.modules.wechat -> app.foundation", @@ -8041,7 +8132,8 @@ "app.modules.wechat.wechatbot -> app.adapters.network.http", "app.modules.wechat.wechatbot -> app.application", "app.modules.wechat.wechatbot -> app.application.messaging", - "app.modules.wechat.wechatbot -> app.application.messaging.agent", + "app.modules.wechat.wechatbot -> app.application.messaging.channel", + "app.modules.wechat.wechatbot -> app.application.messaging.channel.admin", "app.modules.wechat.wechatbot -> app.application.messaging.ingress", "app.modules.wechat.wechatbot -> app.domain", "app.modules.wechat.wechatbot -> app.domain.context", @@ -8057,7 +8149,8 @@ "app.modules.wechat.wechatbot -> app.schemas.types", "app.modules.wechatclawbot -> app.application", "app.modules.wechatclawbot -> app.application.messaging", - "app.modules.wechatclawbot -> app.application.messaging.agent", + "app.modules.wechatclawbot -> app.application.messaging.channel", + "app.modules.wechatclawbot -> app.application.messaging.channel.admin", "app.modules.wechatclawbot -> app.domain", "app.modules.wechatclawbot -> app.domain.context", "app.modules.wechatclawbot -> app.modules", @@ -8115,6 +8208,7 @@ "app.monitor.dispatcher -> app.application", "app.monitor.dispatcher -> app.application.directory", "app.monitor.dispatcher -> app.application.history", + "app.monitor.dispatcher -> app.application.history.retry", "app.monitor.dispatcher -> app.chain", "app.monitor.dispatcher -> app.chain.transfer", "app.monitor.dispatcher -> app.chain.transfer.facade", @@ -9400,6 +9494,8 @@ "app.startup.initializers.modules -> app.application.messaging.agent", "app.startup.initializers.modules -> app.application.messaging.chat", "app.startup.initializers.modules -> app.application.messaging.message", + "app.startup.initializers.modules -> app.application.messaging.webagent", + "app.startup.initializers.modules -> app.application.messaging.webagent.events", "app.startup.initializers.modules -> app.application.module", "app.startup.initializers.modules -> app.application.outbox", "app.startup.initializers.modules -> app.application.plugin", @@ -9814,7 +9910,7 @@ "app.workflow.actions.transfer_file -> app.workflow", "app.workflow.actions.transfer_file -> app.workflow.actions" ], - "module_count": 1025, + "module_count": 1039, "modules": [ "app", "app.adapters", @@ -10064,20 +10160,26 @@ "app.application.download.organization", "app.application.download.selection", "app.application.download.tasks", + "app.application.download.validation", "app.application.downloader", "app.application.filtering", "app.application.formatting", "app.application.history", - "app.application.historymutation", + "app.application.history.contracts", + "app.application.history.mutation", + "app.application.history.retry", "app.application.image", "app.application.invocation", "app.application.maintenance", "app.application.mediaserver", "app.application.messaging", "app.application.messaging.agent", + "app.application.messaging.channel", + "app.application.messaging.channel.admin", "app.application.messaging.chat", "app.application.messaging.ingress", "app.application.messaging.interaction", + "app.application.messaging.interaction.agent", "app.application.messaging.media", "app.application.messaging.message", "app.application.messaging.plugin", @@ -10087,7 +10189,9 @@ "app.application.messaging.skill", "app.application.messaging.subscribe", "app.application.messaging.update", - "app.application.messaging.webagentstream", + "app.application.messaging.webagent", + "app.application.messaging.webagent.events", + "app.application.messaging.webagent.stream", "app.application.module", "app.application.music", "app.application.music.catalog", @@ -10136,6 +10240,7 @@ "app.application.security.userconfig", "app.application.servarr", "app.application.server", + "app.application.server.payload", "app.application.server.report", "app.application.server.share", "app.application.service", @@ -10175,6 +10280,10 @@ "app.application.transfer.execution", "app.application.transfer.feedback", "app.application.transfer.history", + "app.application.transfer.jobs", + "app.application.transfer.models", + "app.application.transfer.notifications", + "app.application.transfer.projection", "app.application.transfer.recovery", "app.application.transfer.workflow", "app.application.workflow", @@ -10391,6 +10500,7 @@ "app.doctor.runner", "app.domain", "app.domain.classification", + "app.domain.classification.conditions", "app.domain.classification.evaluator", "app.domain.classification.facts", "app.domain.classification.fields", diff --git a/tests/fixtures/architecture/filename-policy.json b/tests/fixtures/architecture/filename-policy.json index f2de73511..3fe07beee 100644 --- a/tests/fixtures/architecture/filename-policy.json +++ b/tests/fixtures/architecture/filename-policy.json @@ -55,6 +55,16 @@ "path": "app/application/settings/__init__.py", "reason": "设置包根通过显式懒加载清单保留 app.application.settings 的兼容导入路径,并隔离服务实现与合同模块。" }, + { + "mode": "implementation", + "path": "app/application/history/__init__.py", + "reason": "历史包根集中声明历史用例的公开合同,具体 DTO、Port 和 mutation 实现在单词命名子模块中。" + }, + { + "mode": "implementation", + "path": "app/application/messaging/interaction/__init__.py", + "reason": "交互包根拥有通用会话状态存储和上下文合同,Agent 选择实现位于 agent.py。" + }, { "mode": "implementation", "path": "app/db/models/__init__.py", diff --git a/tests/test_acceleration.py b/tests/test_acceleration.py index a91710a74..90b224807 100644 --- a/tests/test_acceleration.py +++ b/tests/test_acceleration.py @@ -8,7 +8,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.application.transfer import jobs as jobs_module from app.startup.composition import domain as domain_composition @@ -80,7 +80,7 @@ def test_job_task_size_only_reads_missing_local_size(monkeypatch) -> None: """目录大小端口只服务于未携带 size 的本地工作项。""" reader = MagicMock() reader.get_directory_size.return_value = 2048 - monkeypatch.setattr(workflow_module, "_directory_size", reader) + monkeypatch.setattr(jobs_module, "_directory_size", reader) explicit = SimpleNamespace( fileitem=SimpleNamespace(size=1024, storage="local", path="/explicit"), @@ -92,21 +92,21 @@ def test_job_task_size_only_reads_missing_local_size(monkeypatch) -> None: fileitem=SimpleNamespace(size=None, storage="local", path="/downloads"), ) - assert workflow_module._job_task_size(explicit) == 1024 - assert workflow_module._job_task_size(remote) == 0 - assert workflow_module._job_task_size(local) == 2048 + assert jobs_module._job_task_size(explicit) == 1024 + assert jobs_module._job_task_size(remote) == 0 + assert jobs_module._job_task_size(local) == 2048 reader.get_directory_size.assert_called_once_with(Path("/downloads")) def test_job_task_size_requires_reader_for_missing_local_size(monkeypatch) -> None: """本地工作项缺失 size 且端口未装配时必须明确失败。""" - monkeypatch.setattr(workflow_module, "_directory_size", None) + monkeypatch.setattr(jobs_module, "_directory_size", None) local = SimpleNamespace( fileitem=SimpleNamespace(size=None, storage="local", path="/downloads"), ) with pytest.raises(RuntimeError, match="本地目录大小能力尚未由启动组合根配置"): - workflow_module._job_task_size(local) + jobs_module._job_task_size(local) def test_domain_composition_injects_all_system_acceleration_ports(monkeypatch) -> None: diff --git a/tests/test_lifecycle_provider_resets.py b/tests/test_lifecycle_provider_resets.py index 1c74f23d5..fd086e4c1 100644 --- a/tests/test_lifecycle_provider_resets.py +++ b/tests/test_lifecycle_provider_resets.py @@ -479,9 +479,9 @@ def test_outbox_dispatcher_reset_contract() -> None: def test_transfer_history_repository_reset_contract() -> None: """整理历史仓储 factory 撤销后不再暴露旧 lifespan 仓储。""" - from app.application import history as history_module + from app.application.history import contracts as history_contracts - previous = history_module._configured_transfer_history_repository + previous = history_contracts._configured_transfer_history_repository first = object() second = object() try: diff --git a/tests/test_transfer_failure_notification_aggregation.py b/tests/test_transfer_failure_notification_aggregation.py index 2e2d08bf7..86cb1c0ea 100644 --- a/tests/test_transfer_failure_notification_aggregation.py +++ b/tests/test_transfer_failure_notification_aggregation.py @@ -10,7 +10,7 @@ from app.application.transfer.workflow import ( TransferTask, build_transfer_failure_group_key, ) -from app.chain.transfer import TransferChain +from app.chain.transfer.facade import TransferChain from app.domain.context import MediaInfo from app.domain.metainfo import MetaInfo from app.runtime.config import ConfigModel @@ -268,7 +268,7 @@ def test_aggregator_close_observes_flush_callback_error(): loop=loop, ) - with patch("app.application.transfer.workflow.logger.error") as log_error: + with patch("app.application.transfer.notifications.logger.error") as log_error: aggregator.close() callback.assert_called_once_with([notice]) diff --git a/tests/test_transfer_history_legacy_compat.py b/tests/test_transfer_history_legacy_compat.py index a5ae42cb2..96385b182 100644 --- a/tests/test_transfer_history_legacy_compat.py +++ b/tests/test_transfer_history_legacy_compat.py @@ -37,7 +37,7 @@ def test_legacy_transfer_history_oper_preserves_exact_write_abi() -> None: assert public_methods == {"add_success", "add_fail", "add_force"} assert str(inspect.signature(oper_type.add_force)) == ( - "(self, **kwargs) -> app.application.history.TransferHistorySnapshot | None" + "(self, **kwargs) -> app.application.history.contracts.TransferHistorySnapshot | None" ) assert str(inspect.signature(oper_type.add_success)) == ( "(self, fileitem: app.schemas.file.FileItem, mode: str, "