refactor: separate semantic architecture baselines

This commit is contained in:
jxxghp
2026-08-21 19:28:31 +08:00
parent 7bc3ea831f
commit 37c442b042
6 changed files with 872 additions and 630 deletions
+161 -63
View File
@@ -1111,48 +1111,59 @@
"response_model": null
}
],
"plugins.v2/chatgpt/__init__.py": [
"plugins.v2/courseorganizer/__init__.py": [
{
"auth": "'bear'",
"endpoint": "get_cache_stats",
"endpoint_return": "dict",
"endpoint": "get_review_route",
"endpoint_return": "Any",
"methods": [
"GET"
],
"path": "/cache_stats",
"path": "/review",
"response_class": null,
"response_model": null
},
{
"auth": "'bear'",
"endpoint": "clear_cache",
"endpoint_return": "dict",
"endpoint": "save_review_route",
"endpoint_return": "Any",
"methods": [
"GET"
"POST"
],
"path": "/clear_cache",
"path": "/review",
"response_class": null,
"response_model": null
},
{
"auth": "'bear'",
"endpoint": "clear_usage_stats",
"endpoint_return": "dict",
"endpoint": "refresh_review_route",
"endpoint_return": "Any",
"methods": [
"GET"
"POST"
],
"path": "/clear_usage_stats",
"path": "/review/refresh",
"response_class": null,
"response_model": null
},
{
"auth": "'bear'",
"endpoint": "get_usage_stats",
"endpoint_return": "dict",
"endpoint": "associate_tmdb_route",
"endpoint_return": "Any",
"methods": [
"GET"
"POST"
],
"path": "/usage_stats",
"path": "/review/tmdb/associate",
"response_class": null,
"response_model": null
},
{
"auth": "'bear'",
"endpoint": "search_tmdb_route",
"endpoint_return": "Any",
"methods": [
"POST"
],
"path": "/review/tmdb/search",
"response_class": null,
"response_model": null
}
@@ -2501,6 +2512,52 @@
"response_model": null
}
],
"plugins.v3/chatgpt/__init__.py": [
{
"auth": "'bear'",
"endpoint": "get_cache_stats",
"endpoint_return": "dict",
"methods": [
"GET"
],
"path": "/cache_stats",
"response_class": null,
"response_model": null
},
{
"auth": "'bear'",
"endpoint": "clear_cache",
"endpoint_return": "dict",
"methods": [
"GET"
],
"path": "/clear_cache",
"response_class": null,
"response_model": null
},
{
"auth": "'bear'",
"endpoint": "clear_usage_stats",
"endpoint_return": "dict",
"methods": [
"GET"
],
"path": "/clear_usage_stats",
"response_class": null,
"response_model": null
},
{
"auth": "'bear'",
"endpoint": "get_usage_stats",
"endpoint_return": "dict",
"methods": [
"GET"
],
"path": "/usage_stats",
"response_class": null,
"response_model": null
}
],
"plugins.v3/doubanrank/__init__.py": [
{
"auth": null,
@@ -2638,7 +2695,7 @@
]
},
"get_api": {
"file_count": 81,
"file_count": 83,
"files": [
"plugins.v2/agentresourceofficer/__init__.py",
"plugins.v2/agenttokens/__init__.py",
@@ -2656,6 +2713,7 @@
"plugins.v2/clashruleprovider/__init__.py",
"plugins.v2/cleaninvalidseed/__init__.py",
"plugins.v2/contractcheck/__init__.py",
"plugins.v2/courseorganizer/__init__.py",
"plugins.v2/crossseed/__init__.py",
"plugins.v2/dailysummary/__init__.py",
"plugins.v2/doubanrank/__init__.py",
@@ -2708,6 +2766,7 @@
"plugins.v3/autoclean/__init__.py",
"plugins.v3/bangumicoll/__init__.py",
"plugins.v3/brushflow/__init__.py",
"plugins.v3/chatgpt/__init__.py",
"plugins.v3/doubanrank/__init__.py",
"plugins.v3/doubansync/__init__.py",
"plugins.v3/downloadsitetag/__init__.py",
@@ -2728,7 +2787,7 @@
"files": []
},
"get_command": {
"file_count": 79,
"file_count": 81,
"files": [
"plugins.v2/agentresourceofficer/__init__.py",
"plugins.v2/agenttokens/__init__.py",
@@ -2745,6 +2804,7 @@
"plugins.v2/clashruleprovider/__init__.py",
"plugins.v2/cleaninvalidseed/__init__.py",
"plugins.v2/contractcheck/__init__.py",
"plugins.v2/courseorganizer/__init__.py",
"plugins.v2/crossseed/__init__.py",
"plugins.v2/dailysummary/__init__.py",
"plugins.v2/doubanrank/__init__.py",
@@ -2796,6 +2856,7 @@
"plugins.v3/autoclean/__init__.py",
"plugins.v3/bangumicoll/__init__.py",
"plugins.v3/brushflow/__init__.py",
"plugins.v3/chatgpt/__init__.py",
"plugins.v3/doubanrank/__init__.py",
"plugins.v3/doubansync/__init__.py",
"plugins.v3/downloadsitetag/__init__.py",
@@ -2827,7 +2888,7 @@
]
},
"get_form": {
"file_count": 81,
"file_count": 83,
"files": [
"plugins.v2/agentresourceofficer/__init__.py",
"plugins.v2/agenttokens/__init__.py",
@@ -2845,6 +2906,7 @@
"plugins.v2/clashruleprovider/__init__.py",
"plugins.v2/cleaninvalidseed/__init__.py",
"plugins.v2/contractcheck/__init__.py",
"plugins.v2/courseorganizer/__init__.py",
"plugins.v2/crossseed/__init__.py",
"plugins.v2/dailysummary/__init__.py",
"plugins.v2/doubanrank/__init__.py",
@@ -2897,6 +2959,7 @@
"plugins.v3/autoclean/__init__.py",
"plugins.v3/bangumicoll/__init__.py",
"plugins.v3/brushflow/__init__.py",
"plugins.v3/chatgpt/__init__.py",
"plugins.v3/doubanrank/__init__.py",
"plugins.v3/doubansync/__init__.py",
"plugins.v3/downloadsitetag/__init__.py",
@@ -2923,7 +2986,7 @@
]
},
"get_page": {
"file_count": 81,
"file_count": 83,
"files": [
"plugins.v2/agentresourceofficer/__init__.py",
"plugins.v2/agenttokens/__init__.py",
@@ -2941,6 +3004,7 @@
"plugins.v2/clashruleprovider/__init__.py",
"plugins.v2/cleaninvalidseed/__init__.py",
"plugins.v2/contractcheck/__init__.py",
"plugins.v2/courseorganizer/__init__.py",
"plugins.v2/crossseed/__init__.py",
"plugins.v2/dailysummary/__init__.py",
"plugins.v2/doubanrank/__init__.py",
@@ -2993,6 +3057,7 @@
"plugins.v3/autoclean/__init__.py",
"plugins.v3/bangumicoll/__init__.py",
"plugins.v3/brushflow/__init__.py",
"plugins.v3/chatgpt/__init__.py",
"plugins.v3/doubanrank/__init__.py",
"plugins.v3/doubansync/__init__.py",
"plugins.v3/downloadsitetag/__init__.py",
@@ -3009,13 +3074,14 @@
]
},
"get_render_mode": {
"file_count": 11,
"file_count": 12,
"files": [
"plugins.v2/agentresourceofficer/__init__.py",
"plugins.v2/agenttokens/__init__.py",
"plugins.v2/airecognizerenhancer/__init__.py",
"plugins.v2/brushflow/__init__.py",
"plugins.v2/clashruleprovider/__init__.py",
"plugins.v2/courseorganizer/__init__.py",
"plugins.v2/fullscreenposterwall/__init__.py",
"plugins.v2/hrblocker/__init__.py",
"plugins.v2/oidcauth/__init__.py",
@@ -3025,7 +3091,7 @@
]
},
"get_service": {
"file_count": 47,
"file_count": 48,
"files": [
"plugins.v2/agentresourceofficer/__init__.py",
"plugins.v2/autoauction/__init__.py",
@@ -3035,6 +3101,7 @@
"plugins.v2/clashruleprovider/__init__.py",
"plugins.v2/cleaninvalidseed/__init__.py",
"plugins.v2/contractcheck/__init__.py",
"plugins.v2/courseorganizer/__init__.py",
"plugins.v2/crossseed/__init__.py",
"plugins.v2/dailysummary/__init__.py",
"plugins.v2/doubanrank/__init__.py",
@@ -3081,7 +3148,7 @@
"files": []
},
"get_state": {
"file_count": 82,
"file_count": 85,
"files": [
"plugins.v2/agentresourceofficer/__init__.py",
"plugins.v2/agenttokens/__init__.py",
@@ -3100,6 +3167,7 @@
"plugins.v2/clashruleprovider/__init__.py",
"plugins.v2/cleaninvalidseed/__init__.py",
"plugins.v2/contractcheck/__init__.py",
"plugins.v2/courseorganizer/__init__.py",
"plugins.v2/crossseed/__init__.py",
"plugins.v2/dailysummary/__init__.py",
"plugins.v2/doubanrank/__init__.py",
@@ -3152,6 +3220,8 @@
"plugins.v3/autoclean/__init__.py",
"plugins.v3/bangumicoll/__init__.py",
"plugins.v3/brushflow/__init__.py",
"plugins.v3/chatgpt/__init__.py",
"plugins.v3/chatgpt/openai.py",
"plugins.v3/doubanrank/__init__.py",
"plugins.v3/doubansync/__init__.py",
"plugins.v3/downloadsitetag/__init__.py",
@@ -3168,7 +3238,7 @@
]
},
"init_plugin": {
"file_count": 81,
"file_count": 83,
"files": [
"plugins.v2/agentresourceofficer/__init__.py",
"plugins.v2/agenttokens/__init__.py",
@@ -3186,6 +3256,7 @@
"plugins.v2/clashruleprovider/__init__.py",
"plugins.v2/cleaninvalidseed/__init__.py",
"plugins.v2/contractcheck/__init__.py",
"plugins.v2/courseorganizer/__init__.py",
"plugins.v2/crossseed/__init__.py",
"plugins.v2/dailysummary/__init__.py",
"plugins.v2/doubanrank/__init__.py",
@@ -3238,6 +3309,7 @@
"plugins.v3/autoclean/__init__.py",
"plugins.v3/bangumicoll/__init__.py",
"plugins.v3/brushflow/__init__.py",
"plugins.v3/chatgpt/__init__.py",
"plugins.v3/doubanrank/__init__.py",
"plugins.v3/doubansync/__init__.py",
"plugins.v3/downloadsitetag/__init__.py",
@@ -3254,7 +3326,7 @@
]
},
"stop_service": {
"file_count": 81,
"file_count": 83,
"files": [
"plugins.v2/agentresourceofficer/__init__.py",
"plugins.v2/agenttokens/__init__.py",
@@ -3272,6 +3344,7 @@
"plugins.v2/clashruleprovider/__init__.py",
"plugins.v2/cleaninvalidseed/__init__.py",
"plugins.v2/contractcheck/__init__.py",
"plugins.v2/courseorganizer/__init__.py",
"plugins.v2/crossseed/__init__.py",
"plugins.v2/dailysummary/__init__.py",
"plugins.v2/doubanrank/__init__.py",
@@ -3324,6 +3397,7 @@
"plugins.v3/autoclean/__init__.py",
"plugins.v3/bangumicoll/__init__.py",
"plugins.v3/brushflow/__init__.py",
"plugins.v3/chatgpt/__init__.py",
"plugins.v3/doubanrank/__init__.py",
"plugins.v3/doubansync/__init__.py",
"plugins.v3/downloadsitetag/__init__.py",
@@ -3348,11 +3422,12 @@
]
},
"app.agent.llm": {
"file_count": 3,
"file_count": 4,
"files": [
"plugins.v2/airecognizerenhancer/__init__.py",
"plugins.v2/chatgpt/openai.py",
"plugins.v2/qbuploadlimiter/__init__.py"
"plugins.v2/courseorganizer/providers.py",
"plugins.v2/qbuploadlimiter/__init__.py",
"plugins.v3/chatgpt/openai.py"
]
},
"app.agent.llm.helper": {
@@ -3415,10 +3490,11 @@
]
},
"app.chain.media": {
"file_count": 9,
"file_count": 10,
"files": [
"plugins.v2/agentresourceofficer/services/hdhive_openapi.py",
"plugins.v2/airecognizerenhancer/__init__.py",
"plugins.v2/courseorganizer/providers.py",
"plugins.v2/doubanrank/__init__.py",
"plugins.v2/doubansync/__init__.py",
"plugins.v2/lexiannot/__init__.py",
@@ -3548,7 +3624,7 @@
]
},
"app.core.config": {
"file_count": 70,
"file_count": 73,
"files": [
"plugins.v2/agentresourceofficer/__init__.py",
"plugins.v2/agentresourceofficer/services/hdhive_openapi.py",
@@ -3584,6 +3660,7 @@
"plugins.v2/cleaninvalidseed/__init__.py",
"plugins.v2/contractcheck/__init__.py",
"plugins.v2/contractcheck/siteuserinfo/__init__.py",
"plugins.v2/courseorganizer/providers.py",
"plugins.v2/crossseed/__init__.py",
"plugins.v2/dailysummary/__init__.py",
"plugins.v2/doubanrank/__init__.py",
@@ -3594,6 +3671,7 @@
"plugins.v2/ffmpegthumb/__init__.py",
"plugins.v2/fullscreenposterwall/__init__.py",
"plugins.v2/imdbsource/__init__.py",
"plugins.v2/imdbsource/imdbapi.py",
"plugins.v2/imdbsource/imdbhelper.py",
"plugins.v2/invitessignin/__init__.py",
"plugins.v2/iyuuautoseed/__init__.py",
@@ -3619,7 +3697,8 @@
"plugins.v2/tvdbdiscover/__init__.py",
"plugins.v2/tvfirstwatch/__init__.py",
"plugins.v2/updatewechatip/__init__.py",
"plugins.v2/wechatclawbot/__init__.py"
"plugins.v2/wechatclawbot/__init__.py",
"plugins.v3/chatgpt/__init__.py"
]
},
"app.core.context": {
@@ -3645,7 +3724,7 @@
]
},
"app.core.event": {
"file_count": 40,
"file_count": 41,
"files": [
"plugins.v2/agenttokens/__init__.py",
"plugins.v2/airecognizerenhancer/__init__.py",
@@ -3686,7 +3765,8 @@
"plugins.v2/tvfirstwatch/__init__.py",
"plugins.v2/updatewechatip/__init__.py",
"plugins.v2/wechatclawbot/__init__.py",
"plugins.v2/wxpusher/__init__.py"
"plugins.v2/wxpusher/__init__.py",
"plugins.v3/chatgpt/__init__.py"
]
},
"app.core.meta": {
@@ -3880,8 +3960,9 @@
]
},
"app.db.user_oper": {
"file_count": 2,
"file_count": 3,
"files": [
"plugins.v2/courseorganizer/__init__.py",
"plugins.v2/doubansync/__init__.py",
"plugins.v2/oidcauth/__init__.py"
]
@@ -4036,7 +4117,7 @@
]
},
"app.log": {
"file_count": 97,
"file_count": 99,
"files": [
"plugins.v2/agentresourceofficer/__init__.py",
"plugins.v2/agentresourceofficer/feishu_channel.py",
@@ -4082,6 +4163,7 @@
"plugins.v2/contractcheck/__init__.py",
"plugins.v2/contractcheck/siteuserinfo/__init__.py",
"plugins.v2/contractcheck/siteuserinfo/nexus_php.py",
"plugins.v2/courseorganizer/__init__.py",
"plugins.v2/crossseed/__init__.py",
"plugins.v2/dailysummary/__init__.py",
"plugins.v2/doubanrank/__init__.py",
@@ -4134,7 +4216,8 @@
"plugins.v2/updatewechatip/__init__.py",
"plugins.v2/wechatclawbot/__init__.py",
"plugins.v2/wechatclawbot/ilink/client.py",
"plugins.v2/wxpusher/__init__.py"
"plugins.v2/wxpusher/__init__.py",
"plugins.v3/chatgpt/__init__.py"
]
},
"app.modules.bangumi": {
@@ -4210,7 +4293,7 @@
]
},
"app.plugins": {
"file_count": 81,
"file_count": 83,
"files": [
"plugins.v2/agentresourceofficer/__init__.py",
"plugins.v2/agenttokens/__init__.py",
@@ -4228,6 +4311,7 @@
"plugins.v2/clashruleprovider/__init__.py",
"plugins.v2/cleaninvalidseed/__init__.py",
"plugins.v2/contractcheck/__init__.py",
"plugins.v2/courseorganizer/__init__.py",
"plugins.v2/crossseed/__init__.py",
"plugins.v2/dailysummary/__init__.py",
"plugins.v2/doubanrank/__init__.py",
@@ -4280,6 +4364,7 @@
"plugins.v3/autoclean/__init__.py",
"plugins.v3/bangumicoll/__init__.py",
"plugins.v3/brushflow/__init__.py",
"plugins.v3/chatgpt/__init__.py",
"plugins.v3/doubanrank/__init__.py",
"plugins.v3/doubansync/__init__.py",
"plugins.v3/downloadsitetag/__init__.py",
@@ -4322,9 +4407,10 @@
]
},
"app.plugins.chatgpt.openai": {
"file_count": 1,
"file_count": 2,
"files": [
"plugins.v2/chatgpt/__init__.py"
"plugins.v2/chatgpt/__init__.py",
"plugins.v3/chatgpt/__init__.py"
]
},
"app.plugins.ffmpegthumb.ffmpeg_helper": {
@@ -4334,24 +4420,21 @@
]
},
"app.plugins.imdbsource.imdbhelper": {
"file_count": 2,
"file_count": 1,
"files": [
"plugins.v2/imdbsource/__init__.py",
"plugins.v3/imdbsource/__init__.py"
"plugins.v2/imdbsource/__init__.py"
]
},
"app.plugins.imdbsource.officialapi": {
"file_count": 2,
"file_count": 1,
"files": [
"plugins.v2/imdbsource/__init__.py",
"plugins.v3/imdbsource/__init__.py"
"plugins.v2/imdbsource/__init__.py"
]
},
"app.plugins.imdbsource.schema": {
"file_count": 2,
"file_count": 1,
"files": [
"plugins.v2/imdbsource/__init__.py",
"plugins.v3/imdbsource/__init__.py"
"plugins.v2/imdbsource/__init__.py"
]
},
"app.plugins.iyuuautoseed.iyuu_helper": {
@@ -4385,7 +4468,7 @@
]
},
"app.schemas": {
"file_count": 48,
"file_count": 50,
"files": [
"plugins.v2/autoclean/__init__.py",
"plugins.v2/blurayremux/__init__.py",
@@ -4426,9 +4509,11 @@
"plugins.v2/wechatclawbot/__init__.py",
"plugins.v3/autoclean/__init__.py",
"plugins.v3/brushflow/__init__.py",
"plugins.v3/chatgpt/__init__.py",
"plugins.v3/doubanrank/__init__.py",
"plugins.v3/downloadsitetag/__init__.py",
"plugins.v3/imdbsource/__init__.py",
"plugins.v3/imdbsource/schema/imdbapi.py",
"plugins.v3/libraryscraper/__init__.py",
"plugins.v3/maoyanrank/__init__.py",
"plugins.v3/mediaservermsg/__init__.py",
@@ -4437,14 +4522,26 @@
"plugins.v3/tvdbdiscover/__init__.py"
]
},
"app.schemas.context": {
"file_count": 1,
"files": [
"plugins.v3/imdbsource/schema/imdbapi.py"
]
},
"app.schemas.event": {
"file_count": 1,
"files": [
"plugins.v2/hrblocker/__init__.py"
]
},
"app.schemas.exception": {
"file_count": 1,
"files": [
"plugins.v3/imdbsource/officialapi.py"
]
},
"app.schemas.types": {
"file_count": 65,
"file_count": 66,
"files": [
"plugins.v2/agentresourceofficer/__init__.py",
"plugins.v2/agenttokens/__init__.py",
@@ -4500,6 +4597,7 @@
"plugins.v3/autoclean/__init__.py",
"plugins.v3/bangumicoll/__init__.py",
"plugins.v3/brushflow/__init__.py",
"plugins.v3/chatgpt/__init__.py",
"plugins.v3/doubansync/__init__.py",
"plugins.v3/downloadsitetag/__init__.py",
"plugins.v3/episodegroupmeta/__init__.py",
@@ -4522,9 +4620,8 @@
]
},
"app.sdk.cache": {
"file_count": 5,
"file_count": 4,
"files": [
"plugins.v3/imdbsource/__init__.py",
"plugins.v3/imdbsource/imdbapi.py",
"plugins.v3/imdbsource/imdbhelper.py",
"plugins.v3/imdbsource/officialapi.py",
@@ -4532,7 +4629,7 @@
]
},
"app.sdk.config": {
"file_count": 20,
"file_count": 21,
"files": [
"plugins.v3/agentresourceofficer/__init__.py",
"plugins.v3/agentresourceofficer/services/hdhive_openapi.py",
@@ -4546,6 +4643,7 @@
"plugins.v3/downloadsitetag/__init__.py",
"plugins.v3/episodegroupmeta/__init__.py",
"plugins.v3/imdbsource/__init__.py",
"plugins.v3/imdbsource/imdbapi.py",
"plugins.v3/imdbsource/imdbhelper.py",
"plugins.v3/libraryscraper/__init__.py",
"plugins.v3/maoyanrank/__init__.py",
@@ -4573,7 +4671,7 @@
]
},
"app.sdk.logging": {
"file_count": 24,
"file_count": 23,
"files": [
"plugins.v3/agentresourceofficer/__init__.py",
"plugins.v3/agentresourceofficer/feishu_channel.py",
@@ -4588,7 +4686,6 @@
"plugins.v3/downloadsitetag/__init__.py",
"plugins.v3/episodegroupmeta/__init__.py",
"plugins.v3/historytov2/__init__.py",
"plugins.v3/imdbsource/__init__.py",
"plugins.v3/imdbsource/imdbapi.py",
"plugins.v3/imdbsource/imdbhelper.py",
"plugins.v3/imdbsource/officialapi.py",
@@ -4622,7 +4719,7 @@
]
},
"app.sdk.network": {
"file_count": 17,
"file_count": 16,
"files": [
"plugins.v3/animeupscale/__init__.py",
"plugins.v3/bangumicoll/__init__.py",
@@ -4632,7 +4729,6 @@
"plugins.v3/downloadsitetag/__init__.py",
"plugins.v3/episodegroupmeta/__init__.py",
"plugins.v3/historytov2/__init__.py",
"plugins.v3/imdbsource/__init__.py",
"plugins.v3/imdbsource/imdbapi.py",
"plugins.v3/imdbsource/imdbhelper.py",
"plugins.v3/imdbsource/officialapi.py",
@@ -4839,15 +4935,17 @@
]
}
},
"schema_version": 2,
"source": {
"head": "ddb41dbcbbea21196154a7f6d5fdba3aa34a5e4a",
"python_file_count": 231,
"provenance": {
"head": "217c8d25ffe6ff0b3f6352c4278fd6896def442e",
"python_file_count": 237,
"source_sha256": "c3796565ff3fd49a8ff3f1e1373d9afab44fd7b98371e44f662c32739fe53d15"
},
"schema_version": 3,
"scope": {
"repository": "MoviePilot-Plugins",
"roots": [
"plugins.v2",
"plugins.v3"
],
"source_sha256": "63663538bd7f5b7c6a9f318ab58ad35d8c5ab68bd7d798d07a5dcdf600f062ad"
]
}
}
File diff suppressed because it is too large Load Diff
+127
View File
@@ -71,6 +71,133 @@ def test_architecture_plugin_action_requires_repository(capsys):
assert "必须指定 --plugin-repo" in capsys.readouterr().err
def test_architecture_diagnostics_only_support_host_check(capsys):
"""源码位置诊断不得与写操作或插件扫描混用。"""
with pytest.raises(SystemExit) as error:
architecture_baseline.parse_args(["--write-host", "--diagnostics"])
assert error.value.code == 2
assert "只能与 --check-host" in capsys.readouterr().err
def test_runtime_semantics_ignore_line_changes_but_keep_call_count(tmp_path: Path):
"""旧 fixture 的行号变化不影响门禁,重复调用次数仍属于语义。"""
baseline_path = tmp_path / "runtime-contract-baseline.json"
old_value = {
"schema_version": 1,
"run_module": {
"method_count": 1,
"call_count": 2,
"dynamic_call_count": 0,
"methods": {
"search": [
{"caller": "app.chain.search", "line": 10, "mode": "sync"},
{"caller": "app.chain.search", "line": 11, "mode": "sync"},
]
},
"dynamic_calls": [],
},
"events": {
"event_count": 1,
"producer_count": 1,
"consumer_count": 0,
"events": {
"EventType.NoticeMessage": {
"producers": [{"caller": "app.chain.message", "line": 20}],
"consumers": [],
}
},
"dynamic_producers": [],
"dynamic_consumers": [],
},
"sdk_exports": {},
"compat_manifest": {},
}
moved_value = json.loads(json.dumps(old_value))
moved_value["run_module"]["methods"]["search"][0]["line"] = 1000
moved_value["run_module"]["methods"]["search"][1]["line"] = 1001
moved_value["events"]["events"]["EventType.NoticeMessage"]["producers"][0][
"line"
] = 2000
old_semantic = architecture_baseline.semantic_baseline(baseline_path, old_value)
moved_semantic = architecture_baseline.semantic_baseline(
baseline_path,
moved_value,
)
assert old_semantic == moved_semantic
assert old_semantic["run_module"]["methods"]["search"] == [
{"caller": "app.chain.search", "mode": "sync", "count": 2}
]
def test_plugin_provenance_does_not_participate_in_semantic_gate(tmp_path: Path):
"""插件仓 revision 和源码摘要变化不应伪装成 ABI 变化。"""
baseline_path = tmp_path / "official-plugin-baseline.json"
first = {
"schema_version": 3,
"scope": {"repository": "MoviePilot-Plugins", "roots": ["plugins.v3"]},
"provenance": {
"head": "a" * 40,
"python_file_count": 1,
"source_sha256": "a" * 64,
},
"imports": {},
"hooks": {},
"api_routes": {},
}
second = json.loads(json.dumps(first))
second["provenance"] = {
"head": "b" * 40,
"python_file_count": 2,
"source_sha256": "b" * 64,
}
assert architecture_baseline.semantic_baseline(
baseline_path,
first,
) == architecture_baseline.semantic_baseline(baseline_path, second)
def test_plugin_v2_fixture_migrates_before_semantic_comparison(tmp_path: Path):
"""旧插件 fixture 应在内存中迁移,不能因 schema 排列变化误报 ABI。"""
baseline_path = tmp_path / "official-plugin-baseline.json"
old_value = {
"schema_version": 2,
"source": {
"repository": "MoviePilot-Plugins",
"head": "a" * 40,
"roots": ["plugins.v2", "plugins.v3"],
"python_file_count": 1,
"source_sha256": "a" * 64,
},
"imports": {"app.sdk.logging": {"file_count": 1, "files": ["x.py"]}},
"hooks": {},
"api_routes": {},
}
new_value = {
"schema_version": 3,
"scope": {
"repository": "MoviePilot-Plugins",
"roots": ["plugins.v2", "plugins.v3"],
},
"provenance": {
"head": "b" * 40,
"python_file_count": 2,
"source_sha256": "b" * 64,
},
"imports": old_value["imports"],
"hooks": {},
"api_routes": {},
}
assert architecture_baseline.semantic_baseline(
baseline_path,
old_value,
) == architecture_baseline.semantic_baseline(baseline_path, new_value)
def test_architecture_write_host_only_updates_host_files(
tmp_path: Path,
monkeypatch,
+13 -3
View File
@@ -41,9 +41,10 @@ def test_official_plugin_baseline_records_external_source():
baseline_path = BASELINE_ROOT / "official-plugin-baseline.json"
baseline = json.loads(baseline_path.read_text(encoding="utf-8"))
assert baseline["source"]["repository"] == "MoviePilot-Plugins"
assert len(baseline["source"]["head"]) == 40
assert baseline["source"]["roots"] == ["plugins.v2", "plugins.v3"]
assert baseline["schema_version"] == 3
assert baseline["scope"]["repository"] == "MoviePilot-Plugins"
assert baseline["scope"]["roots"] == ["plugins.v2", "plugins.v3"]
assert len(baseline["provenance"]["head"]) == 40
assert all(
not path.startswith("app/plugins/")
for contract in (*baseline["imports"].values(), *baseline["hooks"].values())
@@ -95,6 +96,15 @@ def test_startup_performance_baseline_records_all_cold_import_targets():
assert contract["loaded_module_count"] > 0
def test_runtime_contract_baseline_excludes_diagnostic_line_numbers():
"""运行契约 fixture 只保存稳定语义,源码位置必须按需诊断。"""
baseline_path = BASELINE_ROOT / "runtime-contract-baseline.json"
baseline = json.loads(baseline_path.read_text(encoding="utf-8"))
assert baseline["schema_version"] == 2
assert '"line"' not in json.dumps(baseline)
def test_startup_performance_baseline_records_normal_and_safe_lifecycle_resources():
"""非功能基线必须同时记录正常/安全模式和隔离资源增量。"""
baseline_path = BASELINE_ROOT / "startup-performance-baseline.json"