feat(action): ✨ Add confidence to inline comments#6
Conversation
AI 代码审查汇总PR: #6 (feat(action): ✨ Add confidence to inline comments) 总体评价共发现 13 条可执行问题,建议优先处理 CRITICAL/HIGH。 主要问题(按严重级别)
可执行建议
潜在风险
测试建议
文件级覆盖说明
无法 inline 的已处理项
覆盖状态
未覆盖文件清单:
无 patch 文件覆盖清单:
轮次与预算
|
| }).join(' | '); | ||
| } | ||
|
|
||
| function formatConfidenceValue(confidence) { |
This comment was marked as outdated.
This comment was marked as outdated.
Sorry, something went wrong.
| function formatConfidenceValue(confidence) { | ||
| const value = Number.parseFloat(String(confidence)); | ||
| if (!Number.isFinite(value)) { | ||
| return '0.80'; |
This comment was marked as outdated.
This comment was marked as outdated.
Sorry, something went wrong.
| return { | ||
| suggestionLabel: '建议', | ||
| riskLabel: '风险', | ||
| confidenceLabel: '置信度', |
This comment was marked as outdated.
This comment was marked as outdated.
Sorry, something went wrong.
| } | ||
|
|
||
| function formatConfidenceValue(confidence) { | ||
| const value = Number.parseFloat(String(confidence)); |
This comment was marked as outdated.
This comment was marked as outdated.
Sorry, something went wrong.
| assert.match(body, /Confidence: 0.93/); | ||
| assert.match(body, /ai-code-review-agent:inline-key/); | ||
| assert.match(body, /\[From SubAgent: security\]/); | ||
| assert.ok(body.indexOf('Confidence: 0.93') < body.indexOf('[From SubAgent: security]')); |
This comment was marked as outdated.
This comment was marked as outdated.
Sorry, something went wrong.
| assert.ok(body.indexOf('Confidence: 0.93') < body.indexOf('[From SubAgent: security]')); | ||
| }); | ||
|
|
||
| test('formatConfidenceValue handles invalid and boundary values predictably', () => { |
This comment was marked as outdated.
This comment was marked as outdated.
Sorry, something went wrong.
| side: z.enum(['LEFT', 'RIGHT', 'FILE']).default('RIGHT'), | ||
| line: z.number().int().positive().nullable().default(null), | ||
| confidence: z.number().min(0).max(1).default(0.8), | ||
| confidence: z.number().min(0).max(1).nullable().optional().default(null), |
This comment was marked as outdated.
This comment was marked as outdated.
Sorry, something went wrong.
|
|
||
| function mergeFinding(base, incoming) { | ||
| const preferIncoming = incoming.confidence > base.confidence; | ||
| const baseRank = confidenceRank(base.confidence); |
This comment was marked as outdated.
This comment was marked as outdated.
Sorry, something went wrong.
| const summary = String(finding.summary || '').trim(); | ||
| const confidenceRaw = Number.parseFloat(String(finding.confidence ?? '0.8')); | ||
| const confidence = Number.isFinite(confidenceRaw) ? clamp(confidenceRaw, 0, 1) : 0.8; | ||
| const confidenceRaw = Number.parseFloat(String(finding.confidence)); |
This comment was marked as outdated.
This comment was marked as outdated.
Sorry, something went wrong.
| } | ||
|
|
||
| const confidenceDiff = (b.confidence || 0) - (a.confidence || 0); | ||
| const confidenceDiff = confidenceRank(b.confidence) - confidenceRank(a.confidence); |
This comment was marked as outdated.
This comment was marked as outdated.
Sorry, something went wrong.
| return parsed; | ||
| } | ||
|
|
||
| function parseEnumInput(name, defaultValue, allowedValues) { |
This comment was marked as outdated.
This comment was marked as outdated.
Sorry, something went wrong.
| reviewDimensions: normalizedDimensions, | ||
| reviewLanguage, | ||
| minFindingConfidence: parseFloatRangeInput('min_finding_confidence', 0.72, 0, 1), | ||
| missingConfidencePolicy: parseEnumInput('missing_confidence_policy', 'na', ['drop', 'na', 'fallback']), |
This comment was marked as outdated.
This comment was marked as outdated.
Sorry, something went wrong.
| }).join(' | '); | ||
| } | ||
|
|
||
| function formatConfidenceValue(confidence, unknownValue = 'N/A') { |
This comment was marked as outdated.
This comment was marked as outdated.
Sorry, something went wrong.
| } | ||
|
|
||
| lines.push(`<!-- ai-code-review-agent:inline-key ${inlineKey} -->`); | ||
| lines.push(`${text.confidenceLabel}: ${formatConfidenceValue(finding.confidence, text.unknownConfidenceValue)}`); |
This comment was marked as outdated.
This comment was marked as outdated.
Sorry, something went wrong.
| const degradedText = degradedSummaryOnly | ||
| ? `${text.yes}\n\n${text.reasons}:\n${degradedReasons.map((x) => `- ${x}`).join('\n') || '- unknown'}` | ||
| : text.no; | ||
| const unknownConfidenceFindings = Number.isFinite(coverage.unknownConfidenceFindings) |
This comment was marked as outdated.
This comment was marked as outdated.
Sorry, something went wrong.
| github_token: 'ghs_xxx', | ||
| openai_api_key: 'sk-test', | ||
| min_finding_confidence: '0.85', | ||
| missing_confidence_policy: 'fallback', |
This comment was marked as outdated.
This comment was marked as outdated.
Sorry, something went wrong.
| return parsed; | ||
| } | ||
|
|
||
| function parseEnumInput(name, defaultValue, allowedValues) { |
This comment was marked as outdated.
This comment was marked as outdated.
Sorry, something went wrong.
| side: z.enum(['LEFT', 'RIGHT', 'FILE']).default('RIGHT'), | ||
| line: z.number().int().positive().nullable().default(null), | ||
| confidence: z.number().min(0).max(1).default(0.8), | ||
| confidence: z.number().min(0).max(1).nullable().optional().default(null), |
This comment was marked as outdated.
This comment was marked as outdated.
Sorry, something went wrong.
| reviewDimensions: normalizedDimensions, | ||
| reviewLanguage, | ||
| minFindingConfidence: parseFloatRangeInput('min_finding_confidence', 0.72, 0, 1), | ||
| missingConfidencePolicy: parseEnumInput('missing_confidence_policy', 'na', ['drop', 'na', 'fallback']), |
This comment was marked as outdated.
This comment was marked as outdated.
Sorry, something went wrong.
| }).join(' | '); | ||
| } | ||
|
|
||
| function formatConfidenceValue(confidence, unknownValue = 'N/A') { |
This comment was marked as outdated.
This comment was marked as outdated.
Sorry, something went wrong.
| }), | ||
| config.maxFindings | ||
| ); | ||
| const unknownConfidenceFindings = normalizedFindings.filter((finding) => !Number.isFinite(finding.confidence)).length; |
This comment was marked as outdated.
This comment was marked as outdated.
Sorry, something went wrong.
| ); | ||
| }); | ||
|
|
||
| test('loadConfig normalizes missing_confidence_policy casing and whitespace', () => { |
This comment was marked as outdated.
This comment was marked as outdated.
Sorry, something went wrong.
| assert.equal(formatConfidenceValue('abc'), 'N/A'); | ||
| assert.equal(formatConfidenceValue(-0.1), '0.00'); | ||
| assert.equal(formatConfidenceValue(1.2), '1.00'); | ||
| assert.equal(formatConfidenceValue('0.345'), '0.34'); |
This comment was marked as outdated.
This comment was marked as outdated.
Sorry, something went wrong.
| | `review_language` | no | `English` | Preferred language for review comments and summary | | ||
| | `min_finding_confidence` | no | `0.72` | Keep only findings at or above this confidence (0-1) | | ||
| | `missing_confidence_policy` | no | `na` | Handling for missing/invalid confidence: `drop`, `na`, or `fallback` | | ||
| | `fallback_confidence_value` | no | `0.5` | Fallback confidence used only when `missing_confidence_policy=fallback` | |
This comment was marked as outdated.
This comment was marked as outdated.
Sorry, something went wrong.
| | `uncovered_files` | Number of uncovered files | | ||
| | `degraded` | `true` if summary-only degradation was triggered | | ||
|
|
||
| ## Confidence Semantics |
This comment was marked as outdated.
This comment was marked as outdated.
Sorry, something went wrong.
| const severity = SEVERITY_RANK[incoming.severity] > SEVERITY_RANK[base.severity] | ||
| ? incoming.severity | ||
| : base.severity; | ||
| const mergedConfidence = incomingRank >= baseRank ? incoming.confidence : base.confidence; |
This comment was marked as outdated.
This comment was marked as outdated.
Sorry, something went wrong.
| side: z.enum(['LEFT', 'RIGHT', 'FILE']).default('RIGHT'), | ||
| line: z.number().int().positive().nullable().default(null), | ||
| confidence: z.number().min(0).max(1).default(0.8), | ||
| confidence: z.number().min(0).max(1).nullable().optional().default(null), |
There was a problem hiding this comment.
[MEDIUM] finding schema 从必填数值改为 nullable optional 后缺少兼容性测试
schema 语义变化较大(默认 0.8 -> null),会影响下游过滤/展示逻辑,缺少对应 contract 测试。
建议: 增加 agents/schema 测试:缺失 confidence、显式 null、合法数值、越界数值的解析结果;并验证与 normalize/filter 流程联动行为符合预期。
风险: 上游模型输出轻微变化可能触发解析/过滤行为差异,造成结果数量和质量波动。
置信度: 0.92
| function normalizeFindings(findings, allowedPaths, options = {}) { | ||
| const pathSet = new Set(allowedPaths); | ||
| const minConfidence = Number.isFinite(options.minConfidence) ? options.minConfidence : 0; | ||
| const missingConfidencePolicy = ['drop', 'na', 'fallback'].includes(options.missingConfidencePolicy) |
There was a problem hiding this comment.
[MEDIUM] 默认 na 策略允许未知置信度绕过最小置信度阈值
当 missingConfidencePolicy 默认值为 na 时,confidence 无法解析将被置为 null 并保留;后续阈值判断仅对数值型置信度生效,导致未知置信度不会被 minConfidence 过滤。若上游结果可被操控,可注入大量“未知置信度”发现,降低安全审查可信度。
建议: 将默认策略改为 drop 或 fallback(并设置保守 fallback 值),至少在安全维度下强制 drop;同时增加上游来源可信度校验与速率/数量限制。
风险: 可能造成安全告警结果被噪声淹没、误导人工审计优先级,形成间接安全运营风险。
置信度: 0.90
| return parsed; | ||
| } | ||
|
|
||
| function parseEnumInput(name, defaultValue, allowedValues) { |
There was a problem hiding this comment.
[MEDIUM] 配置新增枚举输入解析缺少非法值与大小写归一化测试
新增 parseEnumInput 并接入关键配置,但未见对默认值、大小写、空白、非法值抛错的测试。
建议: 补充 config 测试:missing_confidence_policy 为 DROP/ na /fallback 归一化成功;非法值报错信息包含输入名与允许列表;未提供输入时走默认 na。
风险: 配置解析异常会导致 action 在运行时直接失败,影响 CI 稳定性。
置信度: 0.96
| }).join(' | '); | ||
| } | ||
|
|
||
| function formatConfidenceValue(confidence, unknownValue = 'N/A') { |
There was a problem hiding this comment.
[MEDIUM] 新增置信度格式化与展示路径缺少针对边界值的单元测试
新增格式化函数包含 NaN/非数值、越界截断与保留两位小数逻辑,但未看到对应测试覆盖,容易在显示层出现回归。
建议: 补充 formatConfidenceValue 单测:null/undefined/''/'abc' 返回 N/A;-0.1=>0.00;1.2=>1.00;0/1/0.345 的格式化结果;并覆盖 buildInlineBody 中置信度行渲染。
风险: 置信度文案错误会误导审查结果解读,且该字段已进入 inline 评论,影响面较大。
置信度: 0.95
| return [ | ||
| text.reviewCompleted, | ||
| `- Findings kept: ${findingsKept}`, | ||
| `- Findings with unknown confidence: ${unknownConfidenceFindings}`, |
There was a problem hiding this comment.
[MEDIUM] Review body 新增字段未国际化,中文模式会出现英文文案
buildReviewBody 新增了 Findings with unknown confidence 的输出,但使用了英文硬编码字符串,没有走 text 语言包。在 review_language=zh 时会与其他中文文案混排,造成可见回归。
建议: 为 review body 的该行新增并使用语言包键(例如 text.unknownConfidenceFindingsLine 或复用已有 unknownConfidenceFindings 标签拼接),避免硬编码英文。
风险: 用户界面语言不一致,降低可读性并影响国际化可维护性;后续新增语言时更易遗漏。
置信度: 0.95
| const degradedText = degradedSummaryOnly | ||
| ? `${text.yes}\n\n${text.reasons}:\n${degradedReasons.map((x) => `- ${x}`).join('\n') || '- unknown'}` | ||
| : text.no; | ||
| const unknownConfidenceFindings = Number.isFinite(coverage.unknownConfidenceFindings) |
There was a problem hiding this comment.
[MEDIUM] Review/Summary 新增 unknownConfidenceFindings 统计缺少一致性测试
unknownConfidenceFindings 被同时用于 summary 与 review body,且有默认值兜底分支;缺少测试验证统计口径和展示一致性。
建议: 增加集成/单测:1) findings 含 null/undefined/NaN/数字时计数正确;2) coverage.unknownConfidenceFindings 缺失时 summary 回退到 0;3) review body 与 summary 数值一致。
风险: 统计不一致会降低结果可信度,用户可能误判模型输出质量。
置信度: 0.90
| /Expected number, received string/ | ||
| ); | ||
|
|
||
| assert.throws( |
There was a problem hiding this comment.
[MEDIUM] createReviewerAgent 对 confidence 边界值仅覆盖上越界,缺少下越界与 NaN/Infinity 场景
schema 测试对 confidence 的非法输入覆盖不完整,当前主要验证类型错误与上界越界。
建议: 补充 assert.throws 用例:confidence=-0.01、NaN、Infinity;并验证错误信息包含范围约束,确保 zod 规则变更时可被检测。
风险: 若实现意外放宽或遗漏下界/非有限数校验,异常值可能穿透到排序/过滤逻辑引发不可预期行为。
置信度: 0.91
| assert.equal(normalized.length, 0); | ||
| }); | ||
|
|
||
| test('normalizeFindings applies fallback confidence and min threshold when policy is fallback', () => { |
There was a problem hiding this comment.
[MEDIUM] 缺少 fallbackConfidenceValue 非法/越界输入的钳制测试
代码对 fallback 值做了 parse + clamp + 默认 0.5 的防御处理,但测试只验证了 0.85 与 0.5 两个正常值,未覆盖 NaN、负数、大于1等关键边界。
建议: 增加参数化测试:fallbackConfidenceValue 分别为 'abc'、-0.1、1.5、null/undefined,断言最终 confidence 分别为 0.5、0、1、0.5,并结合 minConfidence 校验保留/丢弃结果。
风险: 若后续改动破坏 clamp 或默认值逻辑,可能引入异常筛选结果(如把应保留的问题错误过滤)。
置信度: 0.95
| assert.equal(normalized[0].line, null); | ||
| }); | ||
|
|
||
| test('normalizeFindings drops findings with missing confidence when policy is drop', () => { |
There was a problem hiding this comment.
[MEDIUM] 缺少 missingConfidencePolicy 非法值回退到默认 'na' 的测试
实现新增了非法策略值自动回退到 'na' 的逻辑,但当前测试仅覆盖了 drop/fallback/na 显式合法值,未覆盖非法值输入时的默认行为。
建议: 补充用例:missingConfidencePolicy: 'unexpected' 且 minConfidence 生效时,验证缺失/NaN confidence 按 na 语义保留(不参与阈值过滤),并与数值 confidence 的过滤行为并存正确。
风险: 未来重构若误改默认分支(如改为 drop)将导致无 confidence 的 finding 被静默丢弃,现有测试无法及时发现。
置信度: 0.93
| degradedReasons: [] | ||
| }); | ||
|
|
||
| const reviewBody = buildReviewBody({ |
There was a problem hiding this comment.
[MEDIUM] 缺少对 buildReviewBody 在中文与 N/A 语义下的直接测试
新增测试已验证 summary 与 review body 的未知置信度计数一致性,但只覆盖英文固定文案与单一计数,未覆盖中文 bundle、零值、缺省值等关键分支。
建议: 新增 buildReviewBody 的参数化测试:至少覆盖 English/zh-CN、unknownConfidenceFindings 为 0/正数、coverage 缺字段时的降级文案,避免仅靠 summary 测试间接兜底。
风险: 多语言或格式调整时,review body 可能出现文案回退/错译/计数遗漏而测试不报错。
置信度: 0.88
Summary
From SubAgenttag in inline comment bodiesConfidence/置信度) and normalize output to two decimal placesTest Plan
npm run checknpm test🤖 Generated with Codex Cli