refactor: strengthen architecture CI gates and runtime contracts

This commit is contained in:
jxxghp
2026-08-25 17:02:29 +08:00
parent 605bf8174a
commit b914e8b6e4
123 changed files with 4240 additions and 1342 deletions
+12
View File
@@ -0,0 +1,12 @@
{
"application": {
"covered_lines": 0,
"percent": 0.0,
"statements": 0
},
"domain": {
"covered_lines": 0,
"percent": 0.0,
"statements": 0
}
}
+57 -32
View File
@@ -13,8 +13,8 @@
"runtime_to_db": [],
"workflow_to_db": []
},
"edge_count": 6644,
"edge_sha256": "6d011ba65df8afe21dec208fd09a3a2a314743ae282db5ce411307b9d967fd00",
"edge_count": 6661,
"edge_sha256": "e276e75348004a89b7f10f3520ce5eb935130cf11a8b45dc371e79937f5d67e3",
"edges": [
"app -> app.runtime",
"app -> app.runtime.compat",
@@ -1661,7 +1661,7 @@
"app.api.dependencies.workflow -> app.application.scheduling",
"app.api.dependencies.workflow -> app.application.workflow",
"app.api.dependencies.workflow -> app.runtime",
"app.api.dependencies.workflow -> app.runtime.config",
"app.api.dependencies.workflow -> app.runtime.stop",
"app.api.dependencies.workflow -> app.startup",
"app.api.dependencies.workflow -> app.startup.composition",
"app.api.dependencies.workflow -> app.startup.composition.context",
@@ -1700,10 +1700,10 @@
"app.api.endpoints.agent -> app.chain",
"app.api.endpoints.agent -> app.chain.message",
"app.api.endpoints.agent -> app.runtime",
"app.api.endpoints.agent -> app.runtime.config",
"app.api.endpoints.agent -> app.runtime.execution",
"app.api.endpoints.agent -> app.runtime.localization",
"app.api.endpoints.agent -> app.runtime.log",
"app.api.endpoints.agent -> app.runtime.stop",
"app.api.endpoints.agent -> app.schemas",
"app.api.endpoints.agent -> app.schemas.agent",
"app.api.endpoints.agent -> app.schemas.message",
@@ -2316,7 +2316,6 @@
"app.api.endpoints.system -> app.chain.media",
"app.api.endpoints.system -> app.chain.mediaserver",
"app.api.endpoints.system -> app.chain.search",
"app.api.endpoints.system -> app.chain.system",
"app.api.endpoints.system -> app.domain",
"app.api.endpoints.system -> app.domain.metainfo",
"app.api.endpoints.system -> app.foundation",
@@ -2332,6 +2331,7 @@
"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",
@@ -2394,8 +2394,8 @@
"app.api.endpoints.transfer -> app.chain.media",
"app.api.endpoints.transfer -> app.chain.transfer",
"app.api.endpoints.transfer -> app.runtime",
"app.api.endpoints.transfer -> app.runtime.config",
"app.api.endpoints.transfer -> app.runtime.log",
"app.api.endpoints.transfer -> app.runtime.stop",
"app.api.endpoints.transfer -> app.schemas",
"app.api.endpoints.transfer -> app.schemas.common",
"app.api.endpoints.transfer -> app.schemas.response",
@@ -2544,6 +2544,8 @@
"app.application.chain.context -> app.application.chain.data",
"app.application.chain.context -> app.application.chain.durable_events",
"app.application.chain.context -> app.application.configuration",
"app.application.chain.context -> app.runtime",
"app.application.chain.context -> app.runtime.stop",
"app.application.chain.durable_events -> app.application",
"app.application.chain.durable_events -> app.application.history",
"app.application.chain.durable_events -> app.domain",
@@ -2689,8 +2691,8 @@
"app.application.messaging.message -> app.foundation.size",
"app.application.messaging.message -> app.runtime",
"app.application.messaging.message -> app.runtime.cache",
"app.application.messaging.message -> app.runtime.config",
"app.application.messaging.message -> app.runtime.log",
"app.application.messaging.message -> app.runtime.stop",
"app.application.messaging.message -> app.schemas",
"app.application.messaging.message -> app.schemas.message",
"app.application.messaging.message -> app.schemas.tmdb",
@@ -2993,6 +2995,8 @@
"app.chain -> app.schemas.transfer",
"app.chain -> app.schemas.types",
"app.chain -> app.schemas.workflow",
"app.chain._interaction -> app.chain",
"app.chain._interaction -> app.chain._contracts",
"app.chain._interaction -> app.schemas",
"app.chain._interaction -> app.schemas.types",
"app.chain._messaging -> app.application",
@@ -3002,6 +3006,8 @@
"app.chain._messaging -> app.application.messaging.agent",
"app.chain._messaging -> app.application.messaging.message",
"app.chain._messaging -> app.application.notification",
"app.chain._messaging -> app.chain",
"app.chain._messaging -> app.chain._contracts",
"app.chain._messaging -> app.domain",
"app.chain._messaging -> app.domain.context",
"app.chain._messaging -> app.domain.meta",
@@ -3023,6 +3029,7 @@
"app.chain._music -> app.application.subscription.contract",
"app.chain._music -> app.application.torrent",
"app.chain._music -> app.chain",
"app.chain._music -> app.chain._contracts",
"app.chain._music -> app.chain.download",
"app.chain._music -> app.chain.media",
"app.chain._music -> app.chain.search",
@@ -3040,6 +3047,8 @@
"app.chain._recognition -> app.adapters.external.server",
"app.chain._recognition -> app.application",
"app.chain._recognition -> app.application.configuration",
"app.chain._recognition -> app.chain",
"app.chain._recognition -> app.chain._contracts",
"app.chain._recognition -> app.domain",
"app.chain._recognition -> app.domain.context",
"app.chain._recognition -> app.domain.meta",
@@ -3065,6 +3074,7 @@
"app.chain._transfer -> app.application.history",
"app.chain._transfer -> app.application.transfer",
"app.chain._transfer -> app.chain",
"app.chain._transfer -> app.chain._contracts",
"app.chain._transfer -> app.chain.media",
"app.chain._transfer -> app.chain.storage",
"app.chain._transfer -> app.chain.subscribe",
@@ -3139,9 +3149,9 @@
"app.chain.download -> app.foundation.text",
"app.chain.download -> app.runtime",
"app.chain.download -> app.runtime.cache",
"app.chain.download -> app.runtime.config",
"app.chain.download -> app.runtime.events",
"app.chain.download -> app.runtime.log",
"app.chain.download -> app.runtime.stop",
"app.chain.download -> app.runtime.thread",
"app.chain.download -> app.schemas",
"app.chain.download -> app.schemas.event",
@@ -3232,8 +3242,8 @@
"app.chain.mediaserver -> app.application.security.url",
"app.chain.mediaserver -> app.chain",
"app.chain.mediaserver -> app.runtime",
"app.chain.mediaserver -> app.runtime.config",
"app.chain.mediaserver -> app.runtime.log",
"app.chain.mediaserver -> app.runtime.stop",
"app.chain.mediaserver -> app.schemas",
"app.chain.mediaserver -> app.schemas.mediaserver",
"app.chain.mediaserver -> app.schemas.types",
@@ -3286,9 +3296,9 @@
"app.chain.recommend -> app.foundation.singleton",
"app.chain.recommend -> app.runtime",
"app.chain.recommend -> app.runtime.cache",
"app.chain.recommend -> app.runtime.config",
"app.chain.recommend -> app.runtime.execution",
"app.chain.recommend -> app.runtime.log",
"app.chain.recommend -> app.runtime.stop",
"app.chain.recommend -> app.schemas",
"app.chain.recommend -> app.schemas.media",
"app.chain.recommend -> app.schemas.types",
@@ -3337,11 +3347,11 @@
"app.chain.search -> app.foundation.size",
"app.chain.search -> app.foundation.text",
"app.chain.search -> app.runtime",
"app.chain.search -> app.runtime.config",
"app.chain.search -> app.runtime.events",
"app.chain.search -> app.runtime.execution",
"app.chain.search -> app.runtime.log",
"app.chain.search -> app.runtime.progress",
"app.chain.search -> app.runtime.stop",
"app.chain.search -> app.runtime.tasks",
"app.chain.search -> app.schemas",
"app.chain.search -> app.schemas.media",
@@ -3373,9 +3383,9 @@
"app.chain.site -> app.foundation.size",
"app.chain.site -> app.foundation.url",
"app.chain.site -> app.runtime",
"app.chain.site -> app.runtime.config",
"app.chain.site -> app.runtime.events",
"app.chain.site -> app.runtime.log",
"app.chain.site -> app.runtime.stop",
"app.chain.site -> app.schemas",
"app.chain.site -> app.schemas.message",
"app.chain.site -> app.schemas.notification",
@@ -3424,9 +3434,9 @@
"app.chain.subscribe -> app.domain.meta.words",
"app.chain.subscribe -> app.domain.metainfo",
"app.chain.subscribe -> app.runtime",
"app.chain.subscribe -> app.runtime.config",
"app.chain.subscribe -> app.runtime.events",
"app.chain.subscribe -> app.runtime.log",
"app.chain.subscribe -> app.runtime.stop",
"app.chain.subscribe -> app.schemas",
"app.chain.subscribe -> app.schemas.event",
"app.chain.subscribe -> app.schemas.media",
@@ -3479,8 +3489,8 @@
"app.chain.torrents -> app.foundation",
"app.chain.torrents -> app.foundation.text",
"app.chain.torrents -> app.runtime",
"app.chain.torrents -> app.runtime.config",
"app.chain.torrents -> app.runtime.log",
"app.chain.torrents -> app.runtime.stop",
"app.chain.torrents -> app.schemas",
"app.chain.torrents -> app.schemas.media",
"app.chain.torrents -> app.schemas.message",
@@ -3498,6 +3508,7 @@
"app.chain.transfer -> app.chain._transfer",
"app.chain.transfer -> app.chain.media",
"app.chain.transfer -> app.chain.storage",
"app.chain.transfer -> app.chain.subscribe",
"app.chain.transfer -> app.chain.tmdb",
"app.chain.transfer -> app.domain",
"app.chain.transfer -> app.domain.context",
@@ -3513,6 +3524,7 @@
"app.chain.transfer -> app.runtime.log",
"app.chain.transfer -> app.runtime.progress",
"app.chain.transfer -> app.runtime.reload",
"app.chain.transfer -> app.runtime.stop",
"app.chain.transfer -> app.schemas",
"app.chain.transfer -> app.schemas.event",
"app.chain.transfer -> app.schemas.exception",
@@ -3545,10 +3557,10 @@
"app.chain.workflow -> app.application.workflow",
"app.chain.workflow -> app.chain",
"app.chain.workflow -> app.runtime",
"app.chain.workflow -> app.runtime.config",
"app.chain.workflow -> app.runtime.events",
"app.chain.workflow -> app.runtime.execution",
"app.chain.workflow -> app.runtime.log",
"app.chain.workflow -> app.runtime.stop",
"app.chain.workflow -> app.schemas",
"app.chain.workflow -> app.schemas.types",
"app.chain.workflow -> app.schemas.workflow",
@@ -3995,6 +4007,7 @@
"app.main -> app.runtime",
"app.main -> app.runtime.config",
"app.main -> app.runtime.settings",
"app.main -> app.runtime.stop",
"app.main -> app.runtime.topology",
"app.modules -> app.runtime",
"app.modules -> app.runtime.extensions",
@@ -4299,9 +4312,9 @@
"app.modules.filemanager.storages.alipan -> app.modules.filemanager",
"app.modules.filemanager.storages.alipan -> app.modules.filemanager.storages",
"app.modules.filemanager.storages.alipan -> app.runtime",
"app.modules.filemanager.storages.alipan -> app.runtime.config",
"app.modules.filemanager.storages.alipan -> app.runtime.log",
"app.modules.filemanager.storages.alipan -> app.runtime.settings",
"app.modules.filemanager.storages.alipan -> app.runtime.stop",
"app.modules.filemanager.storages.alipan -> app.schemas",
"app.modules.filemanager.storages.alipan -> app.schemas.exception",
"app.modules.filemanager.storages.alipan -> app.schemas.file",
@@ -4318,9 +4331,9 @@
"app.modules.filemanager.storages.alist -> app.modules.filemanager.storages",
"app.modules.filemanager.storages.alist -> app.runtime",
"app.modules.filemanager.storages.alist -> app.runtime.cache",
"app.modules.filemanager.storages.alist -> app.runtime.config",
"app.modules.filemanager.storages.alist -> app.runtime.log",
"app.modules.filemanager.storages.alist -> app.runtime.settings",
"app.modules.filemanager.storages.alist -> app.runtime.stop",
"app.modules.filemanager.storages.alist -> app.schemas",
"app.modules.filemanager.storages.alist -> app.schemas.exception",
"app.modules.filemanager.storages.alist -> app.schemas.file",
@@ -4342,9 +4355,9 @@
"app.modules.filemanager.storages.local -> app.modules.filemanager",
"app.modules.filemanager.storages.local -> app.modules.filemanager.storages",
"app.modules.filemanager.storages.local -> app.runtime",
"app.modules.filemanager.storages.local -> app.runtime.config",
"app.modules.filemanager.storages.local -> app.runtime.log",
"app.modules.filemanager.storages.local -> app.runtime.settings",
"app.modules.filemanager.storages.local -> app.runtime.stop",
"app.modules.filemanager.storages.local -> app.schemas",
"app.modules.filemanager.storages.local -> app.schemas.exception",
"app.modules.filemanager.storages.local -> app.schemas.file",
@@ -4372,9 +4385,9 @@
"app.modules.filemanager.storages.smb -> app.modules.filemanager",
"app.modules.filemanager.storages.smb -> app.modules.filemanager.storages",
"app.modules.filemanager.storages.smb -> app.runtime",
"app.modules.filemanager.storages.smb -> app.runtime.config",
"app.modules.filemanager.storages.smb -> app.runtime.log",
"app.modules.filemanager.storages.smb -> app.runtime.settings",
"app.modules.filemanager.storages.smb -> app.runtime.stop",
"app.modules.filemanager.storages.smb -> app.schemas",
"app.modules.filemanager.storages.smb -> app.schemas.exception",
"app.modules.filemanager.storages.smb -> app.schemas.file",
@@ -4387,10 +4400,10 @@
"app.modules.filemanager.storages.u115 -> app.modules.filemanager",
"app.modules.filemanager.storages.u115 -> app.modules.filemanager.storages",
"app.modules.filemanager.storages.u115 -> app.runtime",
"app.modules.filemanager.storages.u115 -> app.runtime.config",
"app.modules.filemanager.storages.u115 -> app.runtime.log",
"app.modules.filemanager.storages.u115 -> app.runtime.rate",
"app.modules.filemanager.storages.u115 -> app.runtime.settings",
"app.modules.filemanager.storages.u115 -> app.runtime.stop",
"app.modules.filemanager.storages.u115 -> app.schemas",
"app.modules.filemanager.storages.u115 -> app.schemas.exception",
"app.modules.filemanager.storages.u115 -> app.schemas.file",
@@ -5653,6 +5666,7 @@
"app.runtime.config -> app.foundation.url",
"app.runtime.config -> app.runtime",
"app.runtime.config -> app.runtime.log",
"app.runtime.config -> app.runtime.stop",
"app.runtime.config -> app.runtime.version",
"app.runtime.config -> app.schemas",
"app.runtime.config -> app.schemas.types",
@@ -5922,6 +5936,7 @@
"app.scheduler -> app.runtime.progress",
"app.scheduler -> app.runtime.reload",
"app.scheduler -> app.runtime.scheduling",
"app.scheduler -> app.runtime.stop",
"app.scheduler -> app.schemas",
"app.scheduler -> app.schemas.dashboard",
"app.scheduler -> app.schemas.message",
@@ -6354,6 +6369,7 @@
"app.startup.initializers.modules -> app.runtime.observability",
"app.startup.initializers.modules -> app.runtime.settings",
"app.startup.initializers.modules -> app.runtime.state",
"app.startup.initializers.modules -> app.runtime.stop",
"app.startup.initializers.modules -> app.runtime.tasks",
"app.startup.initializers.modules -> app.runtime.thread",
"app.startup.initializers.modules -> app.scheduler",
@@ -6451,6 +6467,7 @@
"app.startup.lifecycle -> app.runtime.log",
"app.startup.lifecycle -> app.runtime.settings",
"app.startup.lifecycle -> app.runtime.state",
"app.startup.lifecycle -> app.runtime.stop",
"app.startup.lifecycle -> app.runtime.tasks",
"app.startup.lifecycle -> app.runtime.topology",
"app.startup.lifecycle -> app.startup",
@@ -6495,6 +6512,7 @@
"app.workflow -> app.runtime.config",
"app.workflow -> app.runtime.events",
"app.workflow -> app.runtime.log",
"app.workflow -> app.runtime.stop",
"app.workflow -> app.schemas",
"app.workflow -> app.schemas.types",
"app.workflow -> app.schemas.workflow",
@@ -6509,8 +6527,8 @@
"app.workflow.actions.add_download -> app.domain",
"app.workflow.actions.add_download -> app.domain.metainfo",
"app.workflow.actions.add_download -> app.runtime",
"app.workflow.actions.add_download -> app.runtime.config",
"app.workflow.actions.add_download -> app.runtime.log",
"app.workflow.actions.add_download -> app.runtime.stop",
"app.workflow.actions.add_download -> app.schemas",
"app.workflow.actions.add_download -> app.schemas.types",
"app.workflow.actions.add_download -> app.schemas.workflow",
@@ -6525,15 +6543,15 @@
"app.workflow.actions.add_subscribe -> app.domain",
"app.workflow.actions.add_subscribe -> app.domain.context",
"app.workflow.actions.add_subscribe -> app.runtime",
"app.workflow.actions.add_subscribe -> app.runtime.config",
"app.workflow.actions.add_subscribe -> app.runtime.log",
"app.workflow.actions.add_subscribe -> app.runtime.stop",
"app.workflow.actions.add_subscribe -> app.schemas",
"app.workflow.actions.add_subscribe -> app.schemas.workflow",
"app.workflow.actions.add_subscribe -> app.workflow",
"app.workflow.actions.add_subscribe -> app.workflow.actions",
"app.workflow.actions.fetch_downloads -> app.runtime",
"app.workflow.actions.fetch_downloads -> app.runtime.config",
"app.workflow.actions.fetch_downloads -> app.runtime.log",
"app.workflow.actions.fetch_downloads -> app.runtime.stop",
"app.workflow.actions.fetch_downloads -> app.schemas",
"app.workflow.actions.fetch_downloads -> app.schemas.workflow",
"app.workflow.actions.fetch_downloads -> app.workflow",
@@ -6546,9 +6564,9 @@
"app.workflow.actions.fetch_medias -> app.chain",
"app.workflow.actions.fetch_medias -> app.chain.recommend",
"app.workflow.actions.fetch_medias -> app.runtime",
"app.workflow.actions.fetch_medias -> app.runtime.config",
"app.workflow.actions.fetch_medias -> app.runtime.events",
"app.workflow.actions.fetch_medias -> app.runtime.log",
"app.workflow.actions.fetch_medias -> app.runtime.stop",
"app.workflow.actions.fetch_medias -> app.schemas",
"app.workflow.actions.fetch_medias -> app.schemas.event",
"app.workflow.actions.fetch_medias -> app.schemas.types",
@@ -6564,8 +6582,8 @@
"app.workflow.actions.fetch_rss -> app.domain.context",
"app.workflow.actions.fetch_rss -> app.domain.metainfo",
"app.workflow.actions.fetch_rss -> app.runtime",
"app.workflow.actions.fetch_rss -> app.runtime.config",
"app.workflow.actions.fetch_rss -> app.runtime.log",
"app.workflow.actions.fetch_rss -> app.runtime.stop",
"app.workflow.actions.fetch_rss -> app.schemas",
"app.workflow.actions.fetch_rss -> app.schemas.workflow",
"app.workflow.actions.fetch_rss -> app.workflow",
@@ -6574,16 +6592,16 @@
"app.workflow.actions.fetch_torrents -> app.chain.media",
"app.workflow.actions.fetch_torrents -> app.chain.search",
"app.workflow.actions.fetch_torrents -> app.runtime",
"app.workflow.actions.fetch_torrents -> app.runtime.config",
"app.workflow.actions.fetch_torrents -> app.runtime.log",
"app.workflow.actions.fetch_torrents -> app.runtime.stop",
"app.workflow.actions.fetch_torrents -> app.schemas",
"app.workflow.actions.fetch_torrents -> app.schemas.types",
"app.workflow.actions.fetch_torrents -> app.schemas.workflow",
"app.workflow.actions.fetch_torrents -> app.workflow",
"app.workflow.actions.fetch_torrents -> app.workflow.actions",
"app.workflow.actions.filter_medias -> app.runtime",
"app.workflow.actions.filter_medias -> app.runtime.config",
"app.workflow.actions.filter_medias -> app.runtime.log",
"app.workflow.actions.filter_medias -> app.runtime.stop",
"app.workflow.actions.filter_medias -> app.schemas",
"app.workflow.actions.filter_medias -> app.schemas.workflow",
"app.workflow.actions.filter_medias -> app.workflow",
@@ -6591,8 +6609,8 @@
"app.workflow.actions.filter_torrents -> app.application",
"app.workflow.actions.filter_torrents -> app.application.torrent",
"app.workflow.actions.filter_torrents -> app.runtime",
"app.workflow.actions.filter_torrents -> app.runtime.config",
"app.workflow.actions.filter_torrents -> app.runtime.log",
"app.workflow.actions.filter_torrents -> app.runtime.stop",
"app.workflow.actions.filter_torrents -> app.schemas",
"app.workflow.actions.filter_torrents -> app.schemas.workflow",
"app.workflow.actions.filter_torrents -> app.workflow",
@@ -6615,8 +6633,8 @@
"app.workflow.actions.scan_file -> app.chain",
"app.workflow.actions.scan_file -> app.chain.storage",
"app.workflow.actions.scan_file -> app.runtime",
"app.workflow.actions.scan_file -> app.runtime.config",
"app.workflow.actions.scan_file -> app.runtime.log",
"app.workflow.actions.scan_file -> app.runtime.stop",
"app.workflow.actions.scan_file -> app.schemas",
"app.workflow.actions.scan_file -> app.schemas.workflow",
"app.workflow.actions.scan_file -> app.workflow",
@@ -6626,8 +6644,8 @@
"app.workflow.actions.scrape_file -> app.chain.scraping",
"app.workflow.actions.scrape_file -> app.chain.storage",
"app.workflow.actions.scrape_file -> app.runtime",
"app.workflow.actions.scrape_file -> app.runtime.config",
"app.workflow.actions.scrape_file -> app.runtime.log",
"app.workflow.actions.scrape_file -> app.runtime.stop",
"app.workflow.actions.scrape_file -> app.schemas",
"app.workflow.actions.scrape_file -> app.schemas.workflow",
"app.workflow.actions.scrape_file -> app.workflow",
@@ -6653,14 +6671,14 @@
"app.workflow.actions.transfer_file -> app.chain.storage",
"app.workflow.actions.transfer_file -> app.chain.transfer",
"app.workflow.actions.transfer_file -> app.runtime",
"app.workflow.actions.transfer_file -> app.runtime.config",
"app.workflow.actions.transfer_file -> app.runtime.log",
"app.workflow.actions.transfer_file -> app.runtime.stop",
"app.workflow.actions.transfer_file -> app.schemas",
"app.workflow.actions.transfer_file -> app.schemas.workflow",
"app.workflow.actions.transfer_file -> app.workflow",
"app.workflow.actions.transfer_file -> app.workflow.actions"
],
"module_count": 816,
"module_count": 818,
"modules": [
"app",
"app.adapters",
@@ -7001,6 +7019,7 @@
"app.application.transfer",
"app.application.workflow",
"app.chain",
"app.chain._contracts",
"app.chain._interaction",
"app.chain._messaging",
"app.chain._music",
@@ -7372,6 +7391,7 @@
"app.runtime.scheduling",
"app.runtime.settings",
"app.runtime.state",
"app.runtime.stop",
"app.runtime.tasks",
"app.runtime.thread",
"app.runtime.topology",
@@ -7482,6 +7502,11 @@
"schema_version": 1,
"scope": "MoviePilot host app excluding app/plugins",
"strongly_connected_components": [
[
"app.chain",
"app.chain._messaging",
"app.chain._recognition"
],
[
"app.modules.themoviedb",
"app.modules.themoviedb.scraper",
File diff suppressed because it is too large Load Diff
+87
View File
@@ -0,0 +1,87 @@
"""Chain mixin Host Protocol 与依赖方向门禁。"""
import ast
from pathlib import Path
from app.chain._contracts import (
ChainRuntimeMixinHost,
InteractionMixinHost,
MusicSubscribeMixinHost,
TransferMixinHost,
)
from app.chain._interaction import InteractionChainMixin
from app.chain._messaging import MessageProcessingMixin, NotificationMixin
from app.chain._music import MusicSubscribeMixin
from app.chain._recognition import RecognitionMixin
from app.chain._transfer import (
EpisodeFormatMixin,
FailedRetryMixin,
FileFilterMixin,
FileKeyMixin,
HistoryMatchMixin,
ManualHistoryMixin,
ScrapeBatchMixin,
)
from app.chain.subscribe import SubscribeChain
from app.chain.transfer import TransferChain
def test_all_chain_mixins_declare_their_host_protocol() -> None:
"""每个存量 Chain mixin 都必须显式声明宿主能力契约。"""
expected = {
RecognitionMixin: ChainRuntimeMixinHost,
MessageProcessingMixin: ChainRuntimeMixinHost,
NotificationMixin: ChainRuntimeMixinHost,
InteractionChainMixin: InteractionMixinHost,
MusicSubscribeMixin: MusicSubscribeMixinHost,
FileFilterMixin: TransferMixinHost,
ScrapeBatchMixin: TransferMixinHost,
EpisodeFormatMixin: TransferMixinHost,
HistoryMatchMixin: TransferMixinHost,
FileKeyMixin: TransferMixinHost,
ManualHistoryMixin: TransferMixinHost,
FailedRetryMixin: TransferMixinHost,
}
assert {
mixin: mixin.__mixin_host_protocol__ for mixin in expected
} == expected
def test_mixin_hosts_provide_injected_chain_factories() -> None:
"""具体 Chain 必须提供 mixin 契约要求的链工厂接缝。"""
for name in (
"_music_media_chain",
"_music_download_chain",
"_music_search_chain",
"_music_site_keywords",
"_matches_music_resource",
):
assert callable(getattr(SubscribeChain, name))
for name in (
"_transfer_media_chain",
"_transfer_storage_chain",
"_transfer_subscribe_chain",
):
assert callable(getattr(TransferChain, name))
def test_domain_mixins_keep_concrete_imports_explicit_until_next_migration() -> None:
"""第一阶段先锁定契约标记,具体导入在后续批次逐步下沉到宿主工厂。"""
root = Path(__file__).resolve().parents[1]
violations = []
for relative in ("app/chain/_music.py", "app/chain/_transfer.py"):
tree = ast.parse((root / relative).read_text(encoding="utf-8"))
for node in ast.walk(tree):
if isinstance(node, ast.ImportFrom) and node.module:
if node.module.startswith("app.chain.") and node.module != "app.chain._contracts":
violations.append(f"{relative}:{node.module}")
assert set(violations) <= {
"app/chain/_music.py:app.chain.download",
"app/chain/_music.py:app.chain.media",
"app/chain/_music.py:app.chain.search",
"app/chain/_transfer.py:app.chain.media",
"app/chain/_transfer.py:app.chain.storage",
"app/chain/_transfer.py:app.chain.subscribe",
}
+78
View File
@@ -0,0 +1,78 @@
"""Ruff 与覆盖率增量门禁测试。"""
from scripts.architecture.coverage_ratchet import (
collect_package_coverage,
compare_coverage,
)
from scripts.architecture.ruff_ratchet import aggregate_diagnostics, compare_counts
def test_ruff_ratchet_rejects_new_rule_and_count_growth() -> None:
"""Ruff 基线允许修复,但拒绝新增规则和既有数量增长。"""
baseline = {"app/example.py": {"F401": 2}}
assert compare_counts(baseline, {"app/example.py": {"F401": 1}}) == []
assert compare_counts(baseline, {"app/example.py": {"F401": 3}}) == [
"app/example.py: Ruff 诊断增长 [F401] 2->3"
]
assert compare_counts(baseline, {"app/new.py": {"I001": 1}}) == [
"app/new.py: 新增 Ruff 诊断 [I001] x1"
]
def test_ruff_diagnostics_are_aggregated_by_relative_file_and_code() -> None:
"""Ruff JSON 的绝对路径必须归一化为稳定仓库路径。"""
from scripts.architecture.ruff_ratchet import PROJECT_ROOT
path = PROJECT_ROOT / "app" / "example.py"
diagnostics = [
{"filename": str(path), "code": "F401"},
{"filename": str(path), "code": "F401"},
{"filename": str(path), "code": "I001"},
]
assert aggregate_diagnostics(diagnostics) == {
"app/example.py": {"F401": 2, "I001": 1}
}
def test_coverage_ratchet_aggregates_governed_packages() -> None:
"""覆盖率门禁只聚合 Application 与 Domain,并按真实语句数加权。"""
report = {
"files": {
"app/application/a.py": {
"summary": {"num_statements": 10, "covered_lines": 8}
},
"app/application/b.py": {
"summary": {"num_statements": 30, "covered_lines": 12}
},
"app/domain/a.py": {
"summary": {"num_statements": 20, "covered_lines": 15}
},
"app/chain/a.py": {
"summary": {"num_statements": 100, "covered_lines": 0}
},
}
}
assert collect_package_coverage(report) == {
"application": {"statements": 40, "covered_lines": 20, "percent": 50.0},
"domain": {"statements": 20, "covered_lines": 15, "percent": 75.0},
}
def test_coverage_ratchet_rejects_only_regressions() -> None:
"""包覆盖率达到或超过阈值时通过,任一包下降时失败。"""
baseline = {
"application": {"percent": 50.0},
"domain": {"percent": 75.0},
}
assert compare_coverage(
baseline,
{"application": {"percent": 50.0}, "domain": {"percent": 76.0}},
) == []
assert compare_coverage(
baseline,
{"application": {"percent": 49.99}, "domain": {"percent": 75.0}},
) == ["application: 行覆盖率下降 50.00%->49.99%"]
+68
View File
@@ -0,0 +1,68 @@
"""进程停止契约和 global_vars 兼容边界测试。"""
import threading
from pathlib import Path
from app.runtime.config import GlobalVar
from app.runtime.stop import ProcessStopState, runtime_stop_state
def test_process_stop_state_separates_repeatable_workflow_and_one_shot_transfer() -> None:
"""工作流停止可恢复,整理路径停止只消费一次。"""
state = ProcessStopState()
state.stop_workflow(7)
assert state.is_workflow_stopped(7)
state.resume_workflow(7)
assert not state.is_workflow_stopped(7)
state.stop_transfer("/media/a.mkv")
assert state.consume_transfer_stop("/media/a.mkv")
assert not state.consume_transfer_stop("/media/a.mkv")
def test_system_stop_propagates_to_all_cancellation_scopes() -> None:
"""系统停止后所有工作流和整理任务都必须立即观察到停止。"""
state = ProcessStopState()
state.stop_system()
assert state.is_system_stopped
assert state.is_workflow_stopped(99)
assert state.consume_transfer_stop("/unknown")
def test_global_vars_stop_api_delegates_to_runtime_contract(monkeypatch) -> None:
"""旧 global_vars ABI 必须与新的显式停止状态共享同一事实源。"""
event = threading.Event()
monkeypatch.setattr(runtime_stop_state, "_system_event", event)
legacy = GlobalVar()
legacy.stop_system()
assert event.is_set()
assert legacy.is_system_stopped
def test_host_code_no_longer_reads_stop_state_from_global_vars() -> None:
"""除兼容实现外,宿主不得重新从 global_vars 读取任何停止信号。"""
root = Path(__file__).resolve().parents[1]
forbidden = (
"global_vars.is_system_stopped",
"global_vars.stop_system",
"global_vars.is_workflow_stopped",
"global_vars.stop_workflow",
"global_vars.workflow_resume",
"global_vars.is_transfer_stopped",
"global_vars.stop_transfer",
)
violations = []
for path in (root / "app").rglob("*.py"):
if path == root / "app/runtime/config.py" or "app/plugins" in path.as_posix():
continue
content = path.read_text(encoding="utf-8")
for expression in forbidden:
if expression in content:
violations.append(f"{path.relative_to(root)}:{expression}")
assert violations == []