跳转至

质量门禁技术债追踪

本文件记录所有门禁豁免及其原因、负责人、预计消除时间、修复方式。任何新增豁免(check_file_length.pySKIP_REL_PATHSeslint.config.jsmax-lines overrides、# noqa# nosec# type: ignore 等)必须同步更新本文件,否则视为违规。

配套文档:Pre-commit 质量门禁手册 自动清单生成:poetry run python scripts/check_file_length.py --list-debt

业务待审核债(非门禁豁免):线下分账待审核技术债


一、文件长度豁免(check_file_length.py / eslint max-lines)

历史 6 个 admin-system 大文件已全部拆分至 500 有效行以内,双份豁免清单已清空(仅保留 seed_data 配置类豁免)。check_file_length.pySKIP_REL_PATHSeslint.config.jsmax-lines overrides 现已无业务文件条目,实现单一来源。

文件 拆分前 拆分后 拆分策略 状态
src/admin-system/src/shared/api/adminApi.ts 1783 ~10(barrel) barrel index → 15 域文件
src/admin-system/src/features/system-config/pages/SystemConfigPage.tsx 571 ~50 3 Tab 组件
src/admin-system/src/features/product-management/components/ProductTree.tsx 698 ~250 主体 + EditModal + utils + SubTreeNodes + SidebarBar
src/admin-system/src/features/product-management/components/ProductManagePanels.tsx 615 ~300 ChildrenPanel + FabricTypePanel + FabricMaterialPanel + panelShared
src/admin-system/src/features/content/ContentManagePage.tsx 567 ~460 主页 + CategoryImageManagerModal + flattenContentTree
src/admin-system/src/features/ai-models/pages/AiModelsPage.tsx 658 187 主页 + AiModelFormPanel + AiModelEditRow + ApiKeyManagerRow + maskKey

配置类豁免(永久)

路径 原因
src/backend/scripts/seed_data 种子/配置数据,非业务代码

拆分手法库(供后续拆分参考)

手法 适用场景 步骤
barrel index 单文件聚合多个域(如 adminApi.ts 按域拆成 domain.ts → 建 index.ts re-export → 原文件退化为 export * from './admin/index' → 外部 import 路径不变
子组件抽取 单大组件含多个独立区块(如 AiModelsPage 识别独立区块 → 抽 props 接口 → 状态下沉到子组件(自管理)或上提到父组件(受控)→ 拆完逐个 typecheck
Tab 拆分 多 Tab 切换页面 每个 Tab 抽独立组件,主页只管 tab 状态与切换壳
utils 抽取 纯函数混在组件文件 移到 utils/ 下纯 .ts 文件,显式标注参数与返回类型
shared 常量 多组件共用图标/标题等 panelShared.ts 等,集中导出

关键注意事项: 1. 拆分时优先保持外部 import 路径不变(barrel re-export),避免大面积改 import 2. 同名类型跨域冲突需重命名(如 TemplateImageMarketingTemplateImage) 3. 每步拆分后立即跑 typecheck + lint + format-check + arch,确认无回归再继续 4. 拆分暴露的隐式 any(原文件内联能推断,跨文件后丢失)需补显式类型标注


二、提交信息规范(commitlint)

仓库引入 @commitlint/config-conventional(见 commitlint.config.cjs),约束 feat / fix / refactor / chore / docs / style / test / perf / build / ci / revert 前缀。

历史迁移说明:仓库早期使用 [FIX] / [FEAT] 方括号风格,自 commitlint 引入起统一为 conventional。历史提交不回填,新提交须符合规范,否则 commit-msg 阶段拒绝。

详见 Pre-commit 手册 · 十一、提交信息规范


三、覆盖率门禁

范围 阈值 配置位置 覆盖范围
后端 80% pyproject.toml [tool.pytest.ini_options] addopts --cov-fail-under=80 backend / messaging / storage / commons
agent-system 80% src/agent-system/vitest.config.ts src/shared + src/app
admin-system 80% src/admin-system/vitest.config.ts src/shared + src/app + src/features/**/utils/**
infinitecanvas 80% src/infinitecanvas/vitest.config.ts 13 个已稳定的 src/utils 纯函数(见下方登记)

后端当前基线(2026-07-04):746 单元测试全过;行覆盖率 80.38%,分支覆盖率 54.46%branch=true 时 pytest 综合指标约 76%)。本轮批量新增约 120+ 测,覆盖计费 Service/Repository、支付适配器、Dypns 短信、Word/库模板 Admin API、用户任务/计费 API、消息 Stream、storage 对象 API 等。

当前状态:adminApi barrel 拆分后,新增的 src/shared/api/admin/*.ts 已通过 coverage.exclude 排除(与原 adminApi.ts 一致),覆盖率门禁维持。infinitecanvas 从零搭起测试基建,首批 13 个 utils 纯函数覆盖率达 97.46%。

收紧路径:后续应逐步为 admin/*.ts 补单测,并在 coverage.include 精确包含已测文件,逐步把覆盖率统计范围从"排除整个 api 目录"放开到"包含已测 api 文件"。

3.1 前端 coverage exclude 登记

下列文件 / 目录经评估依赖网络、复杂状态或运行时渲染,单测成本高,暂通过 coverage.exclude 排除。后续按"修复方式"逐步纳入。

前端 排除项 原因 修复方式 优先级
agent-system src/shared/api/agentApi.ts 薄封装 HTTP 客户端,依赖鉴权与后端 用 MSW mock 鉴权后补 url 构造测试
agent-system src/shared/api/settlementApi.ts 同上,结算接口薄封装 同上
agent-system src/shared/components/** 受控 UI 组件,需 RTL + 交互测试 优先补关键交互组件(Alert、Modal)
agent-system src/app/components/Layout.tsxSidebar.tsx 含路由与权限分支的布局组件 集成测试场景覆盖
admin-system src/shared/api/admin/**adminApi.ts 按 domain 拆分的 API 客户端,依赖网络 MSW mock 后逐个补
admin-system src/shared/api/billingApi.tsadminHttpClient.tswordBatchTestStream.ts 计费 API + 网络传输层(fetch / SSE / FormData) MSW mock 鉴权后补
admin-system src/shared/utils/dualImageUpload.ts 双图上传,依赖 FileReader / FormData 抽纯函数 + MSW
admin-system src/shared/hooks/useFabricMaterialCatalog.ts React Query 网络请求 hook 集成测试 + MSW
admin-system src/shared/components/** 受控 UI 组件库 抽 hook / 纯逻辑到 utils 单测
admin-system src/app/components/Layout.tsxSidebar.tsxTopbar.tsx 含路由与权限分支的布局组件 集成测试场景覆盖
infinitecanvas src/utils 中 API 客户端类(canvas-api-clientrunninghub-apiimage-generation-apicanvas-project-api HTTP 客户端 MSW mock 后补
infinitecanvas src/utils 中状态/序列化类(canvas-persistencecanvas-document-builderselection-groupparent-node-refsimage-tool-processorimage-upload-compressgroup-workflowasset-uploadasset-resolvercanvas-asset-itemsai-input-nodeai-prompt-highlight 依赖画布状态/IndexedDB/文件 IO 抽纯函数 + 集成测试

四、维护规则

  1. 新增豁免 → 在对应章节登记(文件、原因、负责人、预计消除时间、修复方式)
  2. 消除豁免 → 删除条目并同步清空代码侧的豁免配置(SKIP_REL_PATHS / eslint overrides / # noqa 等)
  3. 每月核对 → 由 --list-debt 输出核对,偏差须在此说明
  4. PR 审查 → 新增豁免的 PR 必须在描述中说明理由与消除计划,reviewer 有权拒绝无理豁免

五、已知的预先存在测试债(非门禁豁免,但需修复)

测试文件 问题 影响 修复方式 状态
src/admin-system/tests/unit/app/providers/AuthProvider.test.tsx mock authApi.login/getMe(agent-system 接口),但 admin-system 的 AuthProvider 实际调用 adminLogin(adminApi) ✅ 已修复 重写为 mock adminLoginlocalStorage key 改为 admin_token/admin_user,并在源码 JSON.parse 处加 try/catch 防御损坏数据 ✅ 2026-07 完成
tests/unit/backend/api/test_misc.pyTestStorageApi.test_upload_success httpx.MockTransport + respx 双重 mock,且 respx 试图拦截 ASGITransport 的 client,导致全量 pytest 卡死 ✅ 已修复 改用 monkeypatch.setattr(StorageHttpClient, 'upload_bytes', fake) 直接 mock 类方法,彻底避免 HTTP ✅ 2026-07 完成

六、架构规则修正记录(dependency-cruiser)

本次治理修正了两处规则正则,使其与实际代码结构对齐:

  1. features-no-cross-import:原 (?!\\1) 反向引用在 dependency-cruiser 中无效,改为 pathNot: '^src/features/$1/',正确允许同 feature 内子目录互导、仅禁止跨 feature
  2. no-direct-axios:原 (?!shared/api/httpClient) 仅匹配 httpClient,扩展为 (?:httpClient|adminHttpClient) 覆盖 admin-system 的 adminHttpClient

七、行内豁免速查

代码中常见的"行内豁免"机制,使用时必须在本文件登记:

机制 适用 示例 登记要求
# noqa: <code> Ruff lint import os # noqa: F401 # 注册副作用 本文件登记 code 与原因
# nosec Bandit 安全 subprocess.run(...) # nosec # 输入已白名单 本文件登记 B 规则与原因
# type: ignore[<code>] mypy import x # type: ignore[import-untyped] # 第三方无类型 本文件登记 module 与原因
# alembic:allow-danger: 原因 Alembic 迁移 op.drop_column(...) # alembic:allow-danger: 列已废弃,无数据 行尾必须写原因
SKIP_REL_PATHS 文件长度 scripts/check_file_length.py 本文件第一节登记
eslint overrides ESLint 规则 eslint.config.js 本文件第一节登记

原则:行内豁免是最后的手段,优先重构消除。每条豁免都应有明确的消除路径或充分的永久理由。

7.1 Bandit # nosec 登记

文件 规则 原因 消除计划
src/backend/core/services/model_pool_router.py B311 模型池同优先级账号轮询、层内加权随机选模型,属负载均衡非加密 永久(业务需要伪随机分流)
src/messaging/streams/active_user_registry.py B311 加权轮盘赌抽取高优用户做任务调度,属公平调度非安全场景 永久(业务需要伪随机分流)
src/backend/core/services/queue_sim_engine.py B311 队列仿真引擎会员抽样/延迟抖动/失败率/Key 分配,非加密 永久(仿真专用伪随机)

八、配置漂移校验(待办 / 进行中)

说明 负责人 状态
env ↔ Settings ↔ ConfigMap scripts/check_env_settings_sync.py;CI job Env / Settings Sync 后端负责人 ✅ 已落地
公共基座保护路径 scripts/check_protected_paths.py + .github/CODEOWNERS;PR job Protected Paths 后端负责人 ✅ 已落地
规范文档 docs/standards/config-governance.md 后端负责人 ✅ 已落地

新增配置 KEY 时:先改对应 settings/<domain>.pyenv/.env.<domain>.example,再改 ConfigMap 域文件,最后跑上述脚本。


九、核对命令速查

# 文件长度豁免清单 + 当前行数
poetry run python scripts/check_file_length.py --list-debt

# 全量文件长度检查(零 FAIL 为达标)
poetry run python scripts/check_file_length.py

# 全量 pre-commit 自检
poetry run pre-commit run --all-files

# 单前端全量门禁(含 test + build)
make admin-check
make agent-check

# 后端全量(含 test + cov)
make check