@feng0531/dsh-code-review 0.9.0 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # 变更记录
2
2
 
3
+ ## 0.10.0
4
+
5
+ - 增加findingGroups保守重复报告分组,严格要求复核支持及完整精确证据、触发/影响/解释和展示字段一致;不按模糊标题或部分证据重叠合并。
6
+ - JSON保留全部候选和证据;Markdown仅精简重复说明,保留每处定位、原文和编辑引用。渲染重新核对以免过期分组误折叠。
7
+ - 不新增模型调用,不晋升因果证明,不删除反驳/不确定/未完成候选;四项代码审查增强到此冻结,最终发布核验后停止自主开发。
8
+
3
9
  ## 0.9.0
4
10
 
5
11
  - 完整输入超限时,在已批准检索范围内回退精确hunk窗口;保留原始旧新行号、CRLF及EOF,完整快照用于定位和证据校验。
package/README.md CHANGED
@@ -4,7 +4,11 @@
4
4
 
5
5
  ## 当前状态
6
6
 
7
- 当前代码版本为 0.9.0,包含有界覆盖预检、显式项目规则及候选证据与反证复核;发布状态以 npm 和 GitHub Release 为准。已通过真实临时 Git/SVN 仓库测试,以及隔离进程中的真实 DSH ToolRuntime 注册验证。当前开发会话的实际预览已返回0.6.0的plan/rules字段,空变更预览与默认关闭外发已验证;已进行经宿主审批的六次小规模真实试跑,累计12次模型调用;四组合成正负例与历史修复对照符合预期,历史引入方向检出候选但引用复核未完成(partial)。不是独立盲测或整体质量证明。详情见 [试跑结果](evaluation/PILOT-RESULTS.md)。
7
+ 当前代码版本为 0.10.0,包含有界覆盖预检、显式项目规则及候选证据与反证复核;发布状态以 npm 和 GitHub Release 为准。已通过真实临时 Git/SVN 仓库测试,以及隔离进程中的真实 DSH ToolRuntime 注册验证。当前开发会话的实际预览已返回0.6.0的plan/rules字段,空变更预览与默认关闭外发已验证;已进行经宿主审批的六次小规模真实试跑,累计12次模型调用;四组合成正负例与历史修复对照符合预期,历史引入方向检出候选但引用复核未完成(partial)。不是独立盲测或整体质量证明。详情见 [试跑结果](evaluation/PILOT-RESULTS.md)。
8
+
9
+ ## 保守重复报告归组(0.10.0)
10
+
11
+ 结构化报告保留全部原始 `findings`,附加 `findingGroups` 中的零基发现索引。仅当归因引用有效、复核支持、整套精确证据及标题、触发条件、影响、建议、前后行为和解释一致时归组,不按标题相似、证据部分重叠或传递关系合并。Markdown精简重复说明,仍展示各处定位/原文/变更引用,完整候选与复核证据保留在JSON。不新增模型调用,不证明根因事实,不合并不确定/反驳/未完成发现。
8
12
 
9
13
  ## 证据引用编号(0.7.0)
10
14
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@feng0531/dsh-code-review",
3
- "version": "0.9.0",
3
+ "version": "0.10.0",
4
4
  "private": false,
5
5
  "license": "SEE LICENSE IN LICENSE",
6
6
  "publishConfig": { "access": "public", "registry": "https://registry.npmjs.org/" },
@@ -0,0 +1,14 @@
1
+ // Presentation only. Never removes findings or promotes model causality to fact.
2
+ export function groupDuplicateFindings(findings) {
3
+ const buckets = new Map();
4
+ for (let index = 0; index < findings.length; index++) {
5
+ const f = findings[index], a = f.attribution, v = f.verification;
6
+ if (a?.status !== 'references-validated' || v?.status !== 'completed' || v.verdict !== 'supported' || !v.evidence?.length || v.evidence.some(e => e.status !== 'references-validated')) continue;
7
+ // Require the entire exact evidence set, not mere overlap/transitive similarity.
8
+ const evidence = v.evidence.map(e => JSON.stringify([e.snapshotId, e.sourceId, e.hash, e.start, e.count, e.text])).sort();
9
+ const key = JSON.stringify([f.severity, f.title, f.evidence, f.suggestion, f.trigger, f.impact, a.beforeBehavior, a.afterBehavior, a.reason, v.reason, evidence]);
10
+ if (!buckets.has(key)) buckets.set(key, []);
11
+ buckets.get(key).push(index);
12
+ }
13
+ return [...buckets.values()].filter(indices => indices.length > 1).map((indices, i) => ({ id: 'd' + (i + 1), findingIndices: indices, reason: 'exact-supported-evidence-and-explanation', causality: 'unverified' }));
14
+ }
package/src/review.mjs CHANGED
@@ -1,4 +1,5 @@
1
1
  import { validateWindowFindings } from './window-findings.mjs';
2
+ import { groupDuplicateFindings } from './finding-groups.mjs';
2
3
  import { hash } from './content.mjs';
3
4
  import { coverageFollowup } from './coverage-followup.mjs';
4
5
  import { verificationLoop } from './verification-loop.mjs';
@@ -159,6 +160,7 @@ export async function reviewSnapshot(snapshot, model, options = {}) {
159
160
  report.retrievalUsage = scope.usage();
160
161
  report.retrievalSources = scope.catalog();
161
162
  }
163
+ report.findingGroups = groupDuplicateFindings(report.findings);
162
164
  report.followup = coverageFollowup(report);
163
165
  return report;
164
166
  }
@@ -184,10 +186,22 @@ export function markdownReport(report) {
184
186
  if (report.followup?.suggestedPaths.length) output.push('', '## 后续选择建议', '仅为原快照未完成项;不会自动续审。再次执行需新预览、新审批,并显式选择规则和上下文。阻断项需先处理原因;关联上下文不等于主文件已审查。', ...report.followup.items.filter(item => item.followup).map(item => '- ' + safe(item.path) + ':' + item.status + (item.incompleteVerification ? '(候选复核未完成)' : '')));
185
187
  output.push('', '## 审查发现');
186
188
  if (!report.findings.length) output.push(report.status === 'completed' ? '在已审查范围内未发现具体问题;不代表代码已被证明正确。' : '当前没有有效问题记录,但审查存在未完成项或限制,不能视为通过。');
187
- for (const finding of report.findings) {
189
+ // Recompute from exact data rather than trusting potentially stale group metadata.
190
+ const duplicates = new Map();
191
+ for (const group of groupDuplicateFindings(report.findings)) {
192
+ for (const index of group.findingIndices.slice(1)) duplicates.set(index, group.findingIndices[0]);
193
+ }
194
+ for (const [index, finding] of report.findings.entries()) {
188
195
  const a = finding.anchor;
189
196
  const location = a.kind === 'line' ? a.side + ':' + a.start + '-' + a.end : a.kind === 'property' ? '属性 ' + a.name : '文件级';
190
197
  output.push('', '### [' + finding.severity + '] ' + safe(finding.title), safe(finding.path) + ' · ' + safe(location));
198
+ if (duplicates.has(index)) {
199
+ output.push('- 重复报告候选:与第 ' + (duplicates.get(index) + 1) + ' 条共享完整已校验证据及解释;不证明根因成立。原始候选保留于JSON。');
200
+ output.push('- 本处变更引用:' + safe([...finding.attribution.editIds, ...finding.attribution.properties].join(', ')));
201
+ output.push('- 本处定位原文:' + safe(a.snippet ?? '文件或属性定位'));
202
+ output.push('- 复核状态:模型复核支持;完整证据同前述发现,不是事实或因果证明');
203
+ continue;
204
+ }
191
205
  const verification = finding.verification;
192
206
  if (verification) {
193
207
  const label = verification.status !== 'completed' ? '未完成' : ({ supported: '模型复核支持', refuted: '模型复核反驳(保留候选供追溯)', uncertain: '不确定' }[verification.verdict] ?? '未知');