From 35a19e622a6432548c3a19f3a38807d443e023e5 Mon Sep 17 00:00:00 2001 From: InfinityPacer <160988576+InfinityPacer@users.noreply.github.com> Date: Mon, 31 Aug 2026 10:20:38 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E9=80=9A=E7=9F=A5=E6=B8=A0?= =?UTF-8?q?=E9=81=93=20schema=20=E5=AF=BC=E5=87=BA=E6=B8=85=E5=8D=95=20(#6?= =?UTF-8?q?512)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix(schema): hide uuid factory from exports * chore(architecture): refresh notification dependency baseline * docs(architecture): sync dependency metrics * fix(notification): type configuration schema * chore(architecture): refresh schema dependency snapshot * chore(architecture): sync notification type baselines * chore(architecture): sync coverage snapshot * fix(notification): preserve channel switch schema * chore(schema): refresh export manifest --- app/schemas/exports.py | 1 - app/schemas/system.py | 12 ++++++------ docs/architecture/optimization-checklist.md | 4 ++-- tests/fixtures/architecture/coverage-baseline.json | 4 ++-- tests/fixtures/architecture/mypy-baseline.json | 14 +++++++------- tests/fixtures/architecture/ruff-baseline.json | 3 --- tests/test_agent_query_download_tasks_tool.py | 2 +- tests/test_api_response.py | 2 ++ tests/test_notification_config_identity.py | 11 +++++++++++ 9 files changed, 31 insertions(+), 22 deletions(-) diff --git a/app/schemas/exports.py b/app/schemas/exports.py index 347f517c8..2110a2a05 100644 --- a/app/schemas/exports.py +++ b/app/schemas/exports.py @@ -470,7 +470,6 @@ SCHEMA_EXPORTS = { 'json': ('app.schemas.subscribe', 'json'), 'model_validator': ('app.schemas.transfer', 'model_validator'), 're': ('app.schemas.file', 're'), - 'uuid4': ('app.schemas.system', 'uuid4'), } SCHEMA_CONFLICTS = { diff --git a/app/schemas/system.py b/app/schemas/system.py index cab95223c..5e8b347ac 100644 --- a/app/schemas/system.py +++ b/app/schemas/system.py @@ -1,7 +1,7 @@ from dataclasses import dataclass from datetime import datetime as _DateTime -from typing import Optional, Any, Literal -from uuid import uuid4 +from typing import Any, Literal, Optional +from uuid import uuid4 as _uuid4 from pydantic import BaseModel, Field, field_validator @@ -91,15 +91,15 @@ class NotificationConf(BaseModel): """ # 稳定渠道身份;名称变化时保持不变,用于运行态凭据和跨页面引用。 - id: str = Field(default_factory=lambda: str(uuid4())) + id: str = Field(default_factory=lambda: str(_uuid4())) # 名称 name: Optional[str] = None # 类型 telegram/wechat/feishu/vocechat/synologychat/slack/webpush/qqbot type: Optional[str] = None # 配置 - config: Optional[dict] = Field(default_factory=dict) - # 场景开关 - switchs: Optional[list] = Field(default_factory=list) + config: Optional[dict[str, Any]] = Field(default_factory=dict) + # 场景开关名称列表;NotificationSwitchConf 属于全局通知范围配置,不是渠道字段。 + switchs: Optional[list[str]] = Field(default_factory=list) # 是否启用 enabled: Optional[bool] = False diff --git a/docs/architecture/optimization-checklist.md b/docs/architecture/optimization-checklist.md index ef437c705..43c989906 100644 --- a/docs/architecture/optimization-checklist.md +++ b/docs/architecture/optimization-checklist.md @@ -101,8 +101,8 @@ ARCH-201 至 ARCH-204 均达到实现、验证、提交、推送和远端门禁 | Event Contract | 53 | 均已有 payload model,但当前全部是 diagnostic enforcement | | Python 源码量 | 305,884 行 | 排除 `app/plugins/**`;61 个文件超过 1,000 行,11 个超过 2,000 行 | | 长方法 | 290 个超过 80 行 | AST 统计排除 `app/plugins/**`;65 个超过 150 行,21 个超过 250 行 | -| 全量 mypy 历史债务 | 9,982 / 591 文件 | canonical `SearchChain` Facade 已补齐显式类型转发;strict frontier 当前覆盖 41 个文件,低水位只允许继续下降 | -| Ruff 历史诊断 | 631 | 低水位门禁通过,但规则集只覆盖 `E4/E7/E9/F/I` | +| 全量 mypy 历史债务 | 9,986 / 591 文件 | canonical `SearchChain` Facade 已补齐显式类型转发;strict frontier 当前覆盖 41 个文件,低水位只允许继续下降 | +| Ruff 历史诊断 | 630 | 低水位门禁通过,但规则集只覆盖 `E4/E7/E9/F/I` | | 覆盖率低水位 | Application 81.80%,Domain 81.03% | Chain、Runtime、Agent、Adapter、Startup 未进入包级覆盖率门禁 | ### 3.3 热点文件 diff --git a/tests/fixtures/architecture/coverage-baseline.json b/tests/fixtures/architecture/coverage-baseline.json index d8de22da8..2d095f580 100644 --- a/tests/fixtures/architecture/coverage-baseline.json +++ b/tests/fixtures/architecture/coverage-baseline.json @@ -1,8 +1,8 @@ { "application": { - "covered_lines": 12966, + "covered_lines": 12969, "percent": 81.8, - "statements": 15851 + "statements": 15854 }, "domain": { "covered_lines": 3686, diff --git a/tests/fixtures/architecture/mypy-baseline.json b/tests/fixtures/architecture/mypy-baseline.json index 6acabb803..00be0a09b 100644 --- a/tests/fixtures/architecture/mypy-baseline.json +++ b/tests/fixtures/architecture/mypy-baseline.json @@ -897,8 +897,8 @@ "type-arg": 3 }, "app/api/endpoints/notification.py": { - "misc": 1, - "no-untyped-def": 1 + "misc": 2, + "no-untyped-def": 2 }, "app/api/endpoints/openai.py": { "attr-defined": 1, @@ -1803,7 +1803,7 @@ }, "app/modules/__init__.py": { "assignment": 1, - "attr-defined": 3, + "attr-defined": 4, "empty-body": 4, "misc": 3, "no-any-return": 1, @@ -2856,17 +2856,17 @@ "empty-body": 1, "no-any-return": 1, "no-untyped-call": 1, - "no-untyped-def": 3, + "no-untyped-def": 4, "type-arg": 2, "union-attr": 1 }, "app/modules/wechatclawbot/wechatclawbot.py": { "arg-type": 2, - "assignment": 1, + "assignment": 2, "comparison-overlap": 3, "no-any-return": 3, "no-untyped-def": 4, - "type-arg": 1, + "type-arg": 2, "union-attr": 1 }, "app/modules/zspace/__init__.py": { @@ -3197,7 +3197,7 @@ "app/schemas/system.py": { "assignment": 1, "misc": 15, - "type-arg": 6 + "type-arg": 4 }, "app/schemas/tmdb.py": { "misc": 5 diff --git a/tests/fixtures/architecture/ruff-baseline.json b/tests/fixtures/architecture/ruff-baseline.json index b508f3986..382cb7b08 100644 --- a/tests/fixtures/architecture/ruff-baseline.json +++ b/tests/fixtures/architecture/ruff-baseline.json @@ -717,9 +717,6 @@ "app/schemas/subscribe.py": { "I001": 1 }, - "app/schemas/system.py": { - "I001": 1 - }, "app/schemas/types.py": { "I001": 1 }, diff --git a/tests/test_agent_query_download_tasks_tool.py b/tests/test_agent_query_download_tasks_tool.py index 9ea2b1255..653ed6f11 100644 --- a/tests/test_agent_query_download_tasks_tool.py +++ b/tests/test_agent_query_download_tasks_tool.py @@ -4,7 +4,7 @@ from types import SimpleNamespace from unittest.mock import MagicMock, patch from app.agent.tools.impl.query_download_tasks import QueryDownloadTasksTool -from app.schemas.transfer import DownloadTaskMedia, DownloaderTorrent +from app.schemas.transfer import DownloaderTorrent, DownloadTaskMedia from app.schemas.types import MediaSource diff --git a/tests/test_api_response.py b/tests/test_api_response.py index 285b97e38..a6a23c59e 100644 --- a/tests/test_api_response.py +++ b/tests/test_api_response.py @@ -766,6 +766,8 @@ def test_openapi_success_models_have_no_implicit_empty_nested_schemas(): "Response_Dict_str__Any__", # LLM 提供商管理响应的 data 目录查询为列表、其余动作为映射。 "Response_Union_List_Dict_str__Any____Dict_str__Any___", + # 通知渠道配置由各渠道模块定义,保留动态键值以承载渠道特有选项。 + "NotificationConf", } allowed_empty_components = {"McpJsonRpcEmptyResult"} violations = [] diff --git a/tests/test_notification_config_identity.py b/tests/test_notification_config_identity.py index 11f3649e5..be6a07647 100644 --- a/tests/test_notification_config_identity.py +++ b/tests/test_notification_config_identity.py @@ -20,6 +20,17 @@ def test_notification_config_normalizes_names_and_rejects_duplicates(): ) +def test_notification_channel_switches_keep_string_list_contract(): + """渠道场景开关仍按消息类型名称列表存储并参与匹配。""" + config = NotificationConf( + name="Alpha", + type="telegram", + switchs=["资源下载"], + ) + + assert config.switchs == ["资源下载"] + + def test_reconcile_cached_states_migrates_renamed_identity_and_cleans_removed(monkeypatch): values = {}