ed49b16b0d3a3c4a94eac3120d8bc8ccded6a900f40e89cf90f6d2e9306fe6dca799df9c666e843e本次提交是一个聚焦的功能性修正 + 补测,只涉及评分引擎的「架构驾驭」维度:
| 文件 | 变化类型 | 说明 |
|---|---|---|
lib/scoring/radar.ts | 功能变更 | 架构维新增「代码域门槛」:只有含代码域文件的 push 才计入架构维 |
lib/scoring/__tests__/radar.test.ts | 测试变更 | 改写 1 个用例 + 新增 1 个用例,覆盖纯文档 push 排除与全员纯文档回退 |
提交意图(源码注释):docs/10 §十三 要求「push 内含 ≥1 个领域 ∈ ARCH.CODE_DOMAINS 的文件才计入架构维」;product_docs / other 视为纯文档,纯文档产出不适用架构维;全员纯文档 → archScore = null,Q 按其余维度均值回退(不得退化为 0/5 参与计分)。
lib/scoring/radar.ts(第 267–308 行区段)新增「合格 push」预计算,并在架构维加权循环前做跳过判断:
const codeDomains = new Set(params.ARCH.CODE_DOMAINS);
const pushByCommit = new Map(window.map((c) => [c.id, c.pushId]));
const qualifiedPushIds = new Set<number>();
for (const f of input.files) {
if (!commitIds.has(f.commitId)) continue; // 收窄到窗口内 commit
if (!codeDomains.has(f.domain?.trim() ?? '')) continue; // 仅代码域
const pid = pushByCommit.get(f.commitId);
if (pid != null) qualifiedPushIds.add(pid);
}
...
for (const [pushId, weight] of pushCommits) {
if (!qualifiedPushIds.has(pushId)) continue; // 纯文档 push 排除
...
}
const archScore = archW > 0 ? round2(archWeighted / archW) : null;
关键事实(已核实):
ARCH.CODE_DOMAINS = ['frontend','backend','data','testing','ops','ai_infra'],不含 product_docs、other(lib/scoring/constants.ts:108-109);与 8 领域全集 DOMAIN_LABELS(types/index.ts:170-180)互为「代码域子集」关系。CommitFileRow.domain 类型为 string | null(types/index.ts:51),f.domain?.trim() ?? '' 写法与同文件既有 polishFileStats/depthCoverage 完全一致。input.files 是员工全历史文件(lib/queries.ts:289-292 无时间窗过滤),故循环内 commitIds.has(f.commitId) 检查确有必要,用于收窄到窗口。archScore 类型侧早允许 null(types/index.ts:216 score: number | null),本次只是新增了「全员纯文档」这一产生 null 的路径。lib/scoring/__tests__/radar.test.tsV3.1 纯文档 push 排除 用例:由原来的 domain: 'other' 改为 product_docs,并补齐 graph / repoScale / repoPushHistory,断言架构维 = 8.5(3 个代码 push:难度 7 → 0.5×7 + 0.5×10(治理)),验证纯文档 push 不再稀释分数。V3.1 全员纯文档 用例:断言 dimensions.architecture.score === null 且 factors !== null(Q 回退)。codescan_issues_diff)| 严重度 | 类型 | 位置 | 描述 |
|---|---|---|---|
| Low | Maintainability | lib/scoring/__tests__/radar.test.ts:156 | 重复代码块:4 行重复(2 次出现) |
具体内容:新增用例复用了既有用例中的同一段夹具:
const commitAt = new Date(NOW.getTime() - DAY / 2);
const prevRow = {
repo: 'r', pushId: 1, createdAt: new Date(NOW.getTime() - DAY), density: 10,
cycles: 2, coupling: 0.8, complexity: 30,
};
在 V3.1 两轴架构(第 156 行附近,另见 radar.test.ts:111 已有 3 次重复)与新增的 V3.1 纯文档 push 排除 用例中重复出现。建议抽取为共享 fixture 工厂函数(如 mkArchFixture())以消除重复。
说明:这是测试代码的可维护性问题,不影响运行时行为;且
radar.test.ts本身另有 8 条存量问题(高耦合 fan-out 65、过长行、注释代码过多等),本次仅新增 1 条。源码radar.ts本次未新增任何问题。
codescan_issues_diff)0 条。base → head 之间没有质检问题被修复。
domain ∈ CODE_DOMAINS 的文件才进入 qualifiedPushIds,product_docs / other / 未分类 → 排除。archW === 0 → archScore = null;dimsForQ 仅在非 null 时 push,且 disciplineScore 恒存在,故 dimsForQ.length ≥ 1,Q 不会为空、不会除零(radar.ts:333-338)。balance:scoreList 已 filter((s): s is number => s != null) 过滤 null(radar.ts:385),架构 null 时仅用其余维度。ProfilePanel.tsx:151 用 d.score != null ? d.score.toFixed(1) : "—";ProfilePanel.tsx:127、MemberList.tsx:29 均在 filter(score != null) 后才做算术/渲染。app/api/insight/member-radar/route.ts 原样透传 score。结论:本次改动逻辑正确、类型自洽、下游兼容。
domain 的代码 push 会被排除:门槛完全依赖引擎/Agent 打底的 domain 字段;若某代码文件的 domain 为 null/空串,该 push 不计入架构维,可能导致架构分被低估甚至误为 null。该假设与同文件 polishFileStats / depthCoverage 一致,属既有口径,但建议关注 domain 覆盖率对架构维稳定性的影响。MIN_CODE_PUSHES 为死配置:constants.ts:98 注释声称「代码 push < MIN_CODE_PUSHES(3) → 架构维不适用(null)」,但全仓无任何代码读取该常量(仅定义 + 类型声明 + 无意义透传),实际实现用的是领域口径而非 push 数量口径。仓库自带测试(radar.test.ts 「少量代码 push」2 个 push 仍得 3.5 分)亦佐证该规则未实现。该漂移在本次提交之前即存在,本次 diff 未触碰,建议后续统一「注释/常量」与「实现」口径,或清理死配置。本次 v1.6.39 增量为一次质量良好的小步修正:为架构维补充「代码域门槛」,正确实现「纯文档 push 排除 / 全员纯文档回退」语义,并配套补齐了针对性单测;逻辑、类型、下游 null 处理均已核验通过。未发现新增的功能性缺陷,唯一新增问题为测试代码中的 Low 级重复块;同时顺带暴露出一处存量的注释-实现口径漂移(MIN_CODE_PUSHES 死配置),建议后续处理。