@ktpartners/dgs-platform 2.6.2
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/LICENSE +38 -0
- package/README.md +851 -0
- package/agents/dgs-codebase-cross-analyzer.md +183 -0
- package/agents/dgs-codebase-mapper.md +782 -0
- package/agents/dgs-codebase-synthesizer.md +156 -0
- package/agents/dgs-debugger.md +1256 -0
- package/agents/dgs-executor.md +550 -0
- package/agents/dgs-integration-checker.md +481 -0
- package/agents/dgs-nyquist-auditor.md +178 -0
- package/agents/dgs-phase-researcher.md +563 -0
- package/agents/dgs-phase-verifier.md +450 -0
- package/agents/dgs-plan-checker.md +708 -0
- package/agents/dgs-planner.md +1324 -0
- package/agents/dgs-project-researcher.md +631 -0
- package/agents/dgs-research-synthesizer.md +249 -0
- package/agents/dgs-roadmapper.md +652 -0
- package/agents/dgs-verifier.md +607 -0
- package/bin/install.js +2073 -0
- package/commands/dgs/add-doc.md +45 -0
- package/commands/dgs/add-idea.md +38 -0
- package/commands/dgs/add-phase.md +43 -0
- package/commands/dgs/add-repo.md +54 -0
- package/commands/dgs/add-tests.md +41 -0
- package/commands/dgs/add-todo.md +47 -0
- package/commands/dgs/approve-spec.md +38 -0
- package/commands/dgs/audit-milestone.md +36 -0
- package/commands/dgs/audit-phase.md +37 -0
- package/commands/dgs/cancel-job.md +23 -0
- package/commands/dgs/capture-principle.md +143 -0
- package/commands/dgs/check-todos.md +45 -0
- package/commands/dgs/cleanup.md +18 -0
- package/commands/dgs/complete-milestone.md +136 -0
- package/commands/dgs/complete-project.md +70 -0
- package/commands/dgs/consolidate-ideas.md +50 -0
- package/commands/dgs/create-milestone-job.md +37 -0
- package/commands/dgs/debug.md +164 -0
- package/commands/dgs/develop-idea.md +53 -0
- package/commands/dgs/discuss-idea.md +41 -0
- package/commands/dgs/discuss-phase.md +83 -0
- package/commands/dgs/execute-phase.md +41 -0
- package/commands/dgs/fast.md +38 -0
- package/commands/dgs/find-related-ideas.md +43 -0
- package/commands/dgs/health.md +28 -0
- package/commands/dgs/help.md +22 -0
- package/commands/dgs/import-spec.md +36 -0
- package/commands/dgs/init-product.md +28 -0
- package/commands/dgs/insert-phase.md +32 -0
- package/commands/dgs/join-discord.md +18 -0
- package/commands/dgs/list-docs.md +40 -0
- package/commands/dgs/list-ideas.md +42 -0
- package/commands/dgs/list-jobs.md +22 -0
- package/commands/dgs/list-phase-assumptions.md +46 -0
- package/commands/dgs/list-projects.md +57 -0
- package/commands/dgs/list-specs.md +40 -0
- package/commands/dgs/map-codebase.md +92 -0
- package/commands/dgs/new-milestone.md +44 -0
- package/commands/dgs/new-project.md +42 -0
- package/commands/dgs/node-repair.md +26 -0
- package/commands/dgs/overlap-check.md +20 -0
- package/commands/dgs/pause-work.md +38 -0
- package/commands/dgs/plan-milestone-gaps.md +34 -0
- package/commands/dgs/plan-phase.md +44 -0
- package/commands/dgs/progress.md +24 -0
- package/commands/dgs/quick.md +41 -0
- package/commands/dgs/reactivate-project.md +70 -0
- package/commands/dgs/reapply-patches.md +110 -0
- package/commands/dgs/refine-spec.md +38 -0
- package/commands/dgs/reject-idea.md +43 -0
- package/commands/dgs/remove-doc.md +44 -0
- package/commands/dgs/remove-phase.md +31 -0
- package/commands/dgs/remove-repo.md +69 -0
- package/commands/dgs/research-idea.md +43 -0
- package/commands/dgs/research-phase.md +189 -0
- package/commands/dgs/restore-idea.md +45 -0
- package/commands/dgs/resume-work.md +40 -0
- package/commands/dgs/rollback-job.md +24 -0
- package/commands/dgs/run-job.md +35 -0
- package/commands/dgs/search.md +40 -0
- package/commands/dgs/set-profile.md +34 -0
- package/commands/dgs/settings.md +38 -0
- package/commands/dgs/switch-project.md +58 -0
- package/commands/dgs/undo-consolidation.md +42 -0
- package/commands/dgs/update-idea.md +44 -0
- package/commands/dgs/update.md +37 -0
- package/commands/dgs/validate-phase.md +35 -0
- package/commands/dgs/verify-work.md +39 -0
- package/commands/dgs/write-spec.md +49 -0
- package/deliver-great-systems/.planning/phases/09-backend-wiring-and-error-handling/09-01-SUMMARY.md +84 -0
- package/deliver-great-systems/.planning/phases/09-backend-wiring-and-error-handling/09-02-SUMMARY.md +86 -0
- package/deliver-great-systems/.planning/phases/10-v1-to-v2-migration-flow/10-01-SUMMARY.md +85 -0
- package/deliver-great-systems/bin/dgs-tools.cjs +1444 -0
- package/deliver-great-systems/bin/lib/auto-test.cjs +1365 -0
- package/deliver-great-systems/bin/lib/commands.cjs +570 -0
- package/deliver-great-systems/bin/lib/config.cjs +417 -0
- package/deliver-great-systems/bin/lib/conflict-agent.cjs +1063 -0
- package/deliver-great-systems/bin/lib/conflict-agent.test.cjs +554 -0
- package/deliver-great-systems/bin/lib/context.cjs +929 -0
- package/deliver-great-systems/bin/lib/context.test.cjs +693 -0
- package/deliver-great-systems/bin/lib/core.cjs +744 -0
- package/deliver-great-systems/bin/lib/core.test.cjs +822 -0
- package/deliver-great-systems/bin/lib/docs.cjs +919 -0
- package/deliver-great-systems/bin/lib/docs.test.cjs +211 -0
- package/deliver-great-systems/bin/lib/execution.cjs +705 -0
- package/deliver-great-systems/bin/lib/execution.test.cjs +1472 -0
- package/deliver-great-systems/bin/lib/frontmatter.cjs +324 -0
- package/deliver-great-systems/bin/lib/ideas.cjs +1406 -0
- package/deliver-great-systems/bin/lib/ideas.test.cjs +1417 -0
- package/deliver-great-systems/bin/lib/identity.cjs +125 -0
- package/deliver-great-systems/bin/lib/init.cjs +1114 -0
- package/deliver-great-systems/bin/lib/init.test.cjs +1271 -0
- package/deliver-great-systems/bin/lib/jobs.cjs +2015 -0
- package/deliver-great-systems/bin/lib/jobs.test.cjs +2619 -0
- package/deliver-great-systems/bin/lib/merge-conflicts.cjs +654 -0
- package/deliver-great-systems/bin/lib/merge-conflicts.test.cjs +370 -0
- package/deliver-great-systems/bin/lib/migration.cjs +352 -0
- package/deliver-great-systems/bin/lib/migration.test.cjs +582 -0
- package/deliver-great-systems/bin/lib/milestone.cjs +243 -0
- package/deliver-great-systems/bin/lib/overlap.cjs +437 -0
- package/deliver-great-systems/bin/lib/overlap.test.cjs +747 -0
- package/deliver-great-systems/bin/lib/path-audit.test.cjs +384 -0
- package/deliver-great-systems/bin/lib/paths.cjs +144 -0
- package/deliver-great-systems/bin/lib/paths.test.cjs +486 -0
- package/deliver-great-systems/bin/lib/phase.cjs +910 -0
- package/deliver-great-systems/bin/lib/projects.cjs +691 -0
- package/deliver-great-systems/bin/lib/projects.test.cjs +871 -0
- package/deliver-great-systems/bin/lib/repos.cjs +1432 -0
- package/deliver-great-systems/bin/lib/repos.test.cjs +1882 -0
- package/deliver-great-systems/bin/lib/roadmap.cjs +305 -0
- package/deliver-great-systems/bin/lib/search.cjs +570 -0
- package/deliver-great-systems/bin/lib/specs.cjs +1303 -0
- package/deliver-great-systems/bin/lib/state.cjs +893 -0
- package/deliver-great-systems/bin/lib/template.cjs +228 -0
- package/deliver-great-systems/bin/lib/test-helpers.cjs +291 -0
- package/deliver-great-systems/bin/lib/verify.cjs +796 -0
- package/deliver-great-systems/references/checkpoints.md +776 -0
- package/deliver-great-systems/references/conflict-resolution.md +66 -0
- package/deliver-great-systems/references/context-tiers.md +166 -0
- package/deliver-great-systems/references/continuation-format.md +249 -0
- package/deliver-great-systems/references/decimal-phase-calculation.md +67 -0
- package/deliver-great-systems/references/git-integration.md +250 -0
- package/deliver-great-systems/references/git-planning-commit.md +40 -0
- package/deliver-great-systems/references/model-profile-resolution.md +36 -0
- package/deliver-great-systems/references/model-profiles.md +95 -0
- package/deliver-great-systems/references/phase-argument-parsing.md +61 -0
- package/deliver-great-systems/references/planning-config.md +224 -0
- package/deliver-great-systems/references/questioning.md +162 -0
- package/deliver-great-systems/references/spec-review-loop.md +177 -0
- package/deliver-great-systems/references/tdd.md +265 -0
- package/deliver-great-systems/references/ui-brand.md +160 -0
- package/deliver-great-systems/references/verification-patterns.md +612 -0
- package/deliver-great-systems/templates/DEBUG.md +166 -0
- package/deliver-great-systems/templates/UAT.md +251 -0
- package/deliver-great-systems/templates/VALIDATION.md +95 -0
- package/deliver-great-systems/templates/claude-md.md +74 -0
- package/deliver-great-systems/templates/codebase/architecture.md +257 -0
- package/deliver-great-systems/templates/codebase/concerns.md +312 -0
- package/deliver-great-systems/templates/codebase/conventions.md +309 -0
- package/deliver-great-systems/templates/codebase/integrations.md +282 -0
- package/deliver-great-systems/templates/codebase/stack.md +188 -0
- package/deliver-great-systems/templates/codebase/structure.md +287 -0
- package/deliver-great-systems/templates/codebase/testing.md +482 -0
- package/deliver-great-systems/templates/config.json +38 -0
- package/deliver-great-systems/templates/context.md +354 -0
- package/deliver-great-systems/templates/continue-here.md +80 -0
- package/deliver-great-systems/templates/debug-subagent-prompt.md +93 -0
- package/deliver-great-systems/templates/discovery.md +148 -0
- package/deliver-great-systems/templates/milestone-archive.md +125 -0
- package/deliver-great-systems/templates/milestone.md +117 -0
- package/deliver-great-systems/templates/phase-prompt.md +615 -0
- package/deliver-great-systems/templates/planner-subagent-prompt.md +119 -0
- package/deliver-great-systems/templates/project.md +186 -0
- package/deliver-great-systems/templates/requirements.md +233 -0
- package/deliver-great-systems/templates/research-project/ARCHITECTURE.md +206 -0
- package/deliver-great-systems/templates/research-project/FEATURES.md +149 -0
- package/deliver-great-systems/templates/research-project/PITFALLS.md +202 -0
- package/deliver-great-systems/templates/research-project/STACK.md +122 -0
- package/deliver-great-systems/templates/research-project/SUMMARY.md +172 -0
- package/deliver-great-systems/templates/research.md +554 -0
- package/deliver-great-systems/templates/retrospective.md +54 -0
- package/deliver-great-systems/templates/roadmap.md +204 -0
- package/deliver-great-systems/templates/state.md +178 -0
- package/deliver-great-systems/templates/summary-complex.md +59 -0
- package/deliver-great-systems/templates/summary-minimal.md +41 -0
- package/deliver-great-systems/templates/summary-standard.md +48 -0
- package/deliver-great-systems/templates/summary.md +253 -0
- package/deliver-great-systems/templates/user-setup.md +313 -0
- package/deliver-great-systems/templates/verification-report.md +324 -0
- package/deliver-great-systems/workflows/add-doc.md +151 -0
- package/deliver-great-systems/workflows/add-idea.md +96 -0
- package/deliver-great-systems/workflows/add-phase.md +120 -0
- package/deliver-great-systems/workflows/add-tests.md +359 -0
- package/deliver-great-systems/workflows/add-todo.md +162 -0
- package/deliver-great-systems/workflows/approve-spec.md +194 -0
- package/deliver-great-systems/workflows/audit-milestone.md +364 -0
- package/deliver-great-systems/workflows/audit-phase.md +462 -0
- package/deliver-great-systems/workflows/cancel-job.md +108 -0
- package/deliver-great-systems/workflows/check-todos.md +181 -0
- package/deliver-great-systems/workflows/cleanup.md +247 -0
- package/deliver-great-systems/workflows/codereview.md +526 -0
- package/deliver-great-systems/workflows/complete-milestone.md +1298 -0
- package/deliver-great-systems/workflows/consolidate-ideas.md +365 -0
- package/deliver-great-systems/workflows/create-milestone-job.md +177 -0
- package/deliver-great-systems/workflows/develop-idea.md +544 -0
- package/deliver-great-systems/workflows/diagnose-issues.md +231 -0
- package/deliver-great-systems/workflows/discovery-phase.md +301 -0
- package/deliver-great-systems/workflows/discuss-idea.md +263 -0
- package/deliver-great-systems/workflows/discuss-phase.md +733 -0
- package/deliver-great-systems/workflows/execute-phase.md +571 -0
- package/deliver-great-systems/workflows/execute-plan.md +592 -0
- package/deliver-great-systems/workflows/find-related-ideas.md +271 -0
- package/deliver-great-systems/workflows/health.md +173 -0
- package/deliver-great-systems/workflows/help.md +997 -0
- package/deliver-great-systems/workflows/import-spec.md +381 -0
- package/deliver-great-systems/workflows/init-product.md +767 -0
- package/deliver-great-systems/workflows/insert-phase.md +138 -0
- package/deliver-great-systems/workflows/list-docs.md +119 -0
- package/deliver-great-systems/workflows/list-ideas.md +154 -0
- package/deliver-great-systems/workflows/list-jobs.md +89 -0
- package/deliver-great-systems/workflows/list-phase-assumptions.md +192 -0
- package/deliver-great-systems/workflows/list-specs.md +101 -0
- package/deliver-great-systems/workflows/map-codebase.md +621 -0
- package/deliver-great-systems/workflows/new-milestone.md +591 -0
- package/deliver-great-systems/workflows/new-project.md +1113 -0
- package/deliver-great-systems/workflows/node-repair.md +94 -0
- package/deliver-great-systems/workflows/overlap-check.md +86 -0
- package/deliver-great-systems/workflows/pause-work.md +134 -0
- package/deliver-great-systems/workflows/plan-milestone-gaps.md +306 -0
- package/deliver-great-systems/workflows/plan-phase.md +698 -0
- package/deliver-great-systems/workflows/progress.md +386 -0
- package/deliver-great-systems/workflows/quick.md +845 -0
- package/deliver-great-systems/workflows/refine-spec.md +275 -0
- package/deliver-great-systems/workflows/reject-idea.md +109 -0
- package/deliver-great-systems/workflows/remove-doc.md +117 -0
- package/deliver-great-systems/workflows/remove-phase.md +163 -0
- package/deliver-great-systems/workflows/research-idea.md +325 -0
- package/deliver-great-systems/workflows/research-phase.md +81 -0
- package/deliver-great-systems/workflows/restore-idea.md +101 -0
- package/deliver-great-systems/workflows/resume-project.md +311 -0
- package/deliver-great-systems/workflows/rollback-job.md +130 -0
- package/deliver-great-systems/workflows/run-job.md +498 -0
- package/deliver-great-systems/workflows/search.md +130 -0
- package/deliver-great-systems/workflows/set-profile.md +83 -0
- package/deliver-great-systems/workflows/settings.md +470 -0
- package/deliver-great-systems/workflows/transition.md +563 -0
- package/deliver-great-systems/workflows/undo-consolidation.md +155 -0
- package/deliver-great-systems/workflows/update-idea.md +157 -0
- package/deliver-great-systems/workflows/update.md +242 -0
- package/deliver-great-systems/workflows/validate-phase.md +177 -0
- package/deliver-great-systems/workflows/verify-phase.md +253 -0
- package/deliver-great-systems/workflows/verify-work.md +671 -0
- package/deliver-great-systems/workflows/write-spec.md +450 -0
- package/hooks/dist/dgs-check-update.js +62 -0
- package/hooks/dist/dgs-context-monitor.js +141 -0
- package/hooks/dist/dgs-statusline.js +115 -0
- package/package.json +60 -0
- package/scripts/build-hooks.js +43 -0
|
@@ -0,0 +1,554 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for conflict-agent.cjs pure functions
|
|
3
|
+
*
|
|
4
|
+
* Covers resolution strategy selection (ADDITIVE, DELETION, STRUCTURAL, DIVERGENT),
|
|
5
|
+
* whole-file resolution, semantic conflict detection, cascading learning context,
|
|
6
|
+
* and resolution report generation.
|
|
7
|
+
*
|
|
8
|
+
* Uses Node.js built-in test runner (node:test) and assert (node:assert/strict).
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
const { describe, it } = require('node:test');
|
|
12
|
+
const assert = require('node:assert/strict');
|
|
13
|
+
|
|
14
|
+
const {
|
|
15
|
+
selectResolutionStrategy,
|
|
16
|
+
resolveFileContent,
|
|
17
|
+
detectSemanticConflicts,
|
|
18
|
+
createLearningContext,
|
|
19
|
+
mergeLearningContexts,
|
|
20
|
+
buildResolutionReport,
|
|
21
|
+
} = require('./conflict-agent.cjs');
|
|
22
|
+
|
|
23
|
+
// ─── Helper ──────────────────────────────────────────────────────────────────
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Build a file content string with one or more conflict hunks.
|
|
27
|
+
* @param {Array<{ours: string, theirs: string}>} hunks
|
|
28
|
+
* @returns {string}
|
|
29
|
+
*/
|
|
30
|
+
function buildConflictFile(hunks) {
|
|
31
|
+
const parts = ['// preamble'];
|
|
32
|
+
for (const h of hunks) {
|
|
33
|
+
parts.push('<<<<<<< HEAD');
|
|
34
|
+
if (h.ours) parts.push(h.ours);
|
|
35
|
+
parts.push('=======');
|
|
36
|
+
if (h.theirs) parts.push(h.theirs);
|
|
37
|
+
parts.push('>>>>>>> feature-branch');
|
|
38
|
+
}
|
|
39
|
+
parts.push('// postamble');
|
|
40
|
+
return parts.join('\n');
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// ─── selectResolutionStrategy ────────────────────────────────────────────────
|
|
44
|
+
|
|
45
|
+
describe('selectResolutionStrategy', () => {
|
|
46
|
+
|
|
47
|
+
it('selects theirs for ADDITIVE hunk where ours is empty and theirs has content', () => {
|
|
48
|
+
const hunks = [{
|
|
49
|
+
type: 'ADDITIVE',
|
|
50
|
+
confidence: 'HIGH',
|
|
51
|
+
ours: '',
|
|
52
|
+
theirs: 'const newFeature = true;',
|
|
53
|
+
start_line: 2,
|
|
54
|
+
end_line: 6,
|
|
55
|
+
}];
|
|
56
|
+
const result = selectResolutionStrategy(hunks, null, null);
|
|
57
|
+
assert.equal(result.length, 1);
|
|
58
|
+
assert.equal(result[0].strategy, 'theirs');
|
|
59
|
+
assert.equal(result[0].confidence, 'HIGH');
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it('selects ours for ADDITIVE hunk where theirs is empty and ours has content', () => {
|
|
63
|
+
const hunks = [{
|
|
64
|
+
type: 'ADDITIVE',
|
|
65
|
+
confidence: 'HIGH',
|
|
66
|
+
ours: 'const added = true;',
|
|
67
|
+
theirs: '',
|
|
68
|
+
start_line: 2,
|
|
69
|
+
end_line: 6,
|
|
70
|
+
}];
|
|
71
|
+
const result = selectResolutionStrategy(hunks, null, null);
|
|
72
|
+
assert.equal(result.length, 1);
|
|
73
|
+
assert.equal(result[0].strategy, 'ours');
|
|
74
|
+
assert.equal(result[0].confidence, 'HIGH');
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
it('selects theirs for ADDITIVE hunk where theirs adds new content (superset)', () => {
|
|
78
|
+
const hunks = [{
|
|
79
|
+
type: 'ADDITIVE',
|
|
80
|
+
confidence: 'MEDIUM',
|
|
81
|
+
ours: 'const a = 1;',
|
|
82
|
+
theirs: 'const a = 1;\nconst b = 2;',
|
|
83
|
+
start_line: 2,
|
|
84
|
+
end_line: 8,
|
|
85
|
+
}];
|
|
86
|
+
const result = selectResolutionStrategy(hunks, null, null);
|
|
87
|
+
assert.equal(result.length, 1);
|
|
88
|
+
assert.equal(result[0].strategy, 'theirs');
|
|
89
|
+
assert.equal(result[0].confidence, 'HIGH');
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
it('selects combined for STRUCTURAL hunk with different imports on each side', () => {
|
|
93
|
+
const hunks = [{
|
|
94
|
+
type: 'STRUCTURAL',
|
|
95
|
+
confidence: 'HIGH',
|
|
96
|
+
ours: "const utils = require('./utils.cjs');",
|
|
97
|
+
theirs: "const helpers = require('./helpers.cjs');",
|
|
98
|
+
start_line: 1,
|
|
99
|
+
end_line: 5,
|
|
100
|
+
}];
|
|
101
|
+
const result = selectResolutionStrategy(hunks, null, null);
|
|
102
|
+
assert.equal(result.length, 1);
|
|
103
|
+
assert.equal(result[0].strategy, 'combined');
|
|
104
|
+
assert.ok(result[0].confidence === 'HIGH' || result[0].confidence === 'MEDIUM');
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
it('escalates DIVERGENT hunk without plan context', () => {
|
|
108
|
+
const hunks = [{
|
|
109
|
+
type: 'DIVERGENT',
|
|
110
|
+
confidence: 'LOW',
|
|
111
|
+
ours: 'const mode = "dark";',
|
|
112
|
+
theirs: 'const mode = "light";',
|
|
113
|
+
start_line: 3,
|
|
114
|
+
end_line: 7,
|
|
115
|
+
}];
|
|
116
|
+
const result = selectResolutionStrategy(hunks, null, null);
|
|
117
|
+
assert.equal(result.length, 1);
|
|
118
|
+
assert.equal(result[0].strategy, 'escalate');
|
|
119
|
+
assert.equal(result[0].confidence, 'LOW');
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
it('selects combined for DIVERGENT hunk when plan context is available and no overlapping lines', () => {
|
|
123
|
+
const hunks = [{
|
|
124
|
+
type: 'DIVERGENT',
|
|
125
|
+
confidence: 'LOW',
|
|
126
|
+
ours: 'const timeout = 3000;',
|
|
127
|
+
theirs: 'const retries = 5;',
|
|
128
|
+
start_line: 3,
|
|
129
|
+
end_line: 7,
|
|
130
|
+
}];
|
|
131
|
+
const planContext = [
|
|
132
|
+
{ task_name: 'Update config', action_excerpt: 'adjust settings for both timeout and retries' },
|
|
133
|
+
];
|
|
134
|
+
const result = selectResolutionStrategy(hunks, planContext, null);
|
|
135
|
+
assert.equal(result.length, 1);
|
|
136
|
+
assert.equal(result[0].strategy, 'combined');
|
|
137
|
+
assert.equal(result[0].confidence, 'MEDIUM');
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
it('selects ours (keep-content) for DELETION hunk by default', () => {
|
|
141
|
+
const hunks = [{
|
|
142
|
+
type: 'DELETION',
|
|
143
|
+
confidence: 'HIGH',
|
|
144
|
+
ours: 'const legacy = true;',
|
|
145
|
+
theirs: '',
|
|
146
|
+
start_line: 2,
|
|
147
|
+
end_line: 6,
|
|
148
|
+
}];
|
|
149
|
+
const result = selectResolutionStrategy(hunks, null, null);
|
|
150
|
+
assert.equal(result.length, 1);
|
|
151
|
+
assert.equal(result[0].strategy, 'ours');
|
|
152
|
+
assert.equal(result[0].confidence, 'MEDIUM');
|
|
153
|
+
assert.ok(result[0].reasoning.includes('keeping content'));
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
it('boosts confidence when accumulated learnings match domain', () => {
|
|
157
|
+
const hunks = [{
|
|
158
|
+
type: 'DIVERGENT',
|
|
159
|
+
confidence: 'LOW',
|
|
160
|
+
ours: 'const timeout = 3000;',
|
|
161
|
+
theirs: 'const retries = 5;',
|
|
162
|
+
start_line: 3,
|
|
163
|
+
end_line: 7,
|
|
164
|
+
}];
|
|
165
|
+
const planContext = [
|
|
166
|
+
{ task_name: 'Update config', action_excerpt: 'Adjust timeout and retries' },
|
|
167
|
+
];
|
|
168
|
+
const learnings = {
|
|
169
|
+
files_resolved: ['config.cjs'],
|
|
170
|
+
strategies_used: [{ file: 'config.cjs', strategy: 'combined' }],
|
|
171
|
+
domain_changes: { config: 'Resolved via combined' },
|
|
172
|
+
phase_merges_completed: 1,
|
|
173
|
+
};
|
|
174
|
+
// DIVERGENT with plan context + no overlap => 'combined' at MEDIUM
|
|
175
|
+
// Learnings have 'config' domain, and hunk text doesn't necessarily contain 'config'
|
|
176
|
+
// But timeout/retries text may not match 'config' domain, so let's use matching domain
|
|
177
|
+
const hunks2 = [{
|
|
178
|
+
type: 'DIVERGENT',
|
|
179
|
+
confidence: 'LOW',
|
|
180
|
+
ours: 'const config = { timeout: 3000 };',
|
|
181
|
+
theirs: 'const config = { retries: 5 };',
|
|
182
|
+
start_line: 3,
|
|
183
|
+
end_line: 7,
|
|
184
|
+
}];
|
|
185
|
+
const result = selectResolutionStrategy(hunks2, planContext, learnings);
|
|
186
|
+
assert.equal(result.length, 1);
|
|
187
|
+
// DIVERGENT with context and overlapping 'config' line => escalate because overlap
|
|
188
|
+
// Let's use non-overlapping lines that contain 'config' in their text
|
|
189
|
+
const hunks3 = [{
|
|
190
|
+
type: 'DELETION',
|
|
191
|
+
confidence: 'HIGH',
|
|
192
|
+
ours: 'const config_timeout = 3000;',
|
|
193
|
+
theirs: '',
|
|
194
|
+
start_line: 3,
|
|
195
|
+
end_line: 7,
|
|
196
|
+
}];
|
|
197
|
+
const result2 = selectResolutionStrategy(hunks3, null, learnings);
|
|
198
|
+
// DELETION default => ours, MEDIUM confidence
|
|
199
|
+
// Learnings domain 'config' matches 'config_timeout' in ours text
|
|
200
|
+
// MEDIUM boosted to HIGH
|
|
201
|
+
assert.equal(result2[0].strategy, 'ours');
|
|
202
|
+
assert.equal(result2[0].confidence, 'HIGH');
|
|
203
|
+
assert.ok(result2[0].reasoning.includes('boosted'));
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
it('handles multiple hunks returning strategy per hunk', () => {
|
|
207
|
+
const hunks = [
|
|
208
|
+
{ type: 'ADDITIVE', confidence: 'HIGH', ours: '', theirs: 'new line', start_line: 2, end_line: 6 },
|
|
209
|
+
{ type: 'DELETION', confidence: 'HIGH', ours: 'old line', theirs: '', start_line: 8, end_line: 12 },
|
|
210
|
+
{ type: 'DIVERGENT', confidence: 'LOW', ours: 'const a = 1;', theirs: 'const a = 2;', start_line: 14, end_line: 18 },
|
|
211
|
+
];
|
|
212
|
+
const result = selectResolutionStrategy(hunks, null, null);
|
|
213
|
+
assert.equal(result.length, 3);
|
|
214
|
+
assert.equal(result[0].hunk_index, 0);
|
|
215
|
+
assert.equal(result[1].hunk_index, 1);
|
|
216
|
+
assert.equal(result[2].hunk_index, 2);
|
|
217
|
+
assert.equal(result[0].strategy, 'theirs'); // ADDITIVE, ours empty
|
|
218
|
+
assert.equal(result[1].strategy, 'ours'); // DELETION, keep content
|
|
219
|
+
assert.equal(result[2].strategy, 'escalate'); // DIVERGENT, no context
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
// ─── resolveFileContent ──────────────────────────────────────────────────────
|
|
225
|
+
|
|
226
|
+
describe('resolveFileContent', () => {
|
|
227
|
+
|
|
228
|
+
it('resolves ours strategy by keeping ours content', () => {
|
|
229
|
+
const content = buildConflictFile([{ ours: 'const x = 1;', theirs: 'const x = 2;' }]);
|
|
230
|
+
const strategies = [{ hunk_index: 0, strategy: 'ours' }];
|
|
231
|
+
const result = resolveFileContent(content, strategies, null);
|
|
232
|
+
assert.ok(result.resolved_content.includes('const x = 1;'));
|
|
233
|
+
assert.ok(!result.resolved_content.includes('const x = 2;'));
|
|
234
|
+
assert.ok(!result.resolved_content.includes('<<<<<<<'));
|
|
235
|
+
assert.equal(result.applied, 1);
|
|
236
|
+
assert.equal(result.escalated, 0);
|
|
237
|
+
assert.equal(result.has_unresolved, false);
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
it('resolves theirs strategy by keeping theirs content', () => {
|
|
241
|
+
const content = buildConflictFile([{ ours: 'const x = 1;', theirs: 'const x = 2;' }]);
|
|
242
|
+
const strategies = [{ hunk_index: 0, strategy: 'theirs' }];
|
|
243
|
+
const result = resolveFileContent(content, strategies, null);
|
|
244
|
+
assert.ok(result.resolved_content.includes('const x = 2;'));
|
|
245
|
+
assert.ok(!result.resolved_content.includes('const x = 1;'));
|
|
246
|
+
assert.ok(!result.resolved_content.includes('<<<<<<<'));
|
|
247
|
+
assert.equal(result.applied, 1);
|
|
248
|
+
assert.equal(result.escalated, 0);
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
it('resolves combined strategy by concatenating both sides', () => {
|
|
252
|
+
const content = buildConflictFile([{ ours: 'const a = 1;', theirs: 'const b = 2;' }]);
|
|
253
|
+
const strategies = [{ hunk_index: 0, strategy: 'combined' }];
|
|
254
|
+
const result = resolveFileContent(content, strategies, null);
|
|
255
|
+
assert.ok(result.resolved_content.includes('const a = 1;'));
|
|
256
|
+
assert.ok(result.resolved_content.includes('const b = 2;'));
|
|
257
|
+
assert.ok(!result.resolved_content.includes('<<<<<<<'));
|
|
258
|
+
assert.equal(result.applied, 1);
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
it('leaves escalated hunks with conflict markers', () => {
|
|
262
|
+
const content = buildConflictFile([{ ours: 'const x = 1;', theirs: 'const x = 2;' }]);
|
|
263
|
+
const strategies = [{ hunk_index: 0, strategy: 'escalate' }];
|
|
264
|
+
const result = resolveFileContent(content, strategies, null);
|
|
265
|
+
assert.ok(result.resolved_content.includes('<<<<<<< ours'));
|
|
266
|
+
assert.ok(result.resolved_content.includes('======='));
|
|
267
|
+
assert.ok(result.resolved_content.includes('>>>>>>> theirs'));
|
|
268
|
+
assert.equal(result.has_unresolved, true);
|
|
269
|
+
assert.equal(result.escalated, 1);
|
|
270
|
+
assert.equal(result.applied, 0);
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
it('handles multi-hunk file with mixed strategies', () => {
|
|
274
|
+
const content = buildConflictFile([
|
|
275
|
+
{ ours: 'const a = 1;', theirs: 'const a = 2;' },
|
|
276
|
+
{ ours: 'const b = 10;', theirs: 'const b = 20;' },
|
|
277
|
+
{ ours: 'const c = 100;', theirs: 'const c = 200;' },
|
|
278
|
+
]);
|
|
279
|
+
const strategies = [
|
|
280
|
+
{ hunk_index: 0, strategy: 'ours' },
|
|
281
|
+
{ hunk_index: 1, strategy: 'theirs' },
|
|
282
|
+
{ hunk_index: 2, strategy: 'combined' },
|
|
283
|
+
];
|
|
284
|
+
const result = resolveFileContent(content, strategies, null);
|
|
285
|
+
assert.ok(result.resolved_content.includes('const a = 1;')); // ours
|
|
286
|
+
assert.ok(!result.resolved_content.includes('const a = 2;'));
|
|
287
|
+
assert.ok(result.resolved_content.includes('const b = 20;')); // theirs
|
|
288
|
+
assert.ok(!result.resolved_content.includes('const b = 10;'));
|
|
289
|
+
assert.ok(result.resolved_content.includes('const c = 100;')); // combined
|
|
290
|
+
assert.ok(result.resolved_content.includes('const c = 200;'));
|
|
291
|
+
assert.equal(result.applied, 3);
|
|
292
|
+
assert.equal(result.escalated, 0);
|
|
293
|
+
assert.equal(result.has_unresolved, false);
|
|
294
|
+
});
|
|
295
|
+
|
|
296
|
+
it('deduplicates require lines in combined structural resolution', () => {
|
|
297
|
+
const oursImports = "const fs = require('fs');\nconst path = require('path');";
|
|
298
|
+
const theirsImports = "const path = require('path');\nconst os = require('os');";
|
|
299
|
+
const content = buildConflictFile([{ ours: oursImports, theirs: theirsImports }]);
|
|
300
|
+
const strategies = [{ hunk_index: 0, strategy: 'combined' }];
|
|
301
|
+
const result = resolveFileContent(content, strategies, null);
|
|
302
|
+
// Should deduplicate: path appears once, sorted alphabetically
|
|
303
|
+
const lines = result.resolved_content.split('\n');
|
|
304
|
+
const requireLines = lines.filter(l => l.includes('require('));
|
|
305
|
+
assert.equal(requireLines.length, 3, 'Should have 3 unique require lines (fs, os, path)');
|
|
306
|
+
// Check alphabetical order
|
|
307
|
+
const requireTexts = requireLines.map(l => l.trim());
|
|
308
|
+
const sorted = [...requireTexts].sort((a, b) => a.localeCompare(b));
|
|
309
|
+
assert.deepEqual(requireTexts, sorted, 'Require lines should be alphabetically sorted');
|
|
310
|
+
assert.equal(result.applied, 1);
|
|
311
|
+
});
|
|
312
|
+
|
|
313
|
+
it('returns correct applied and escalated counts', () => {
|
|
314
|
+
const content = buildConflictFile([
|
|
315
|
+
{ ours: 'line1', theirs: 'line2' },
|
|
316
|
+
{ ours: 'line3', theirs: 'line4' },
|
|
317
|
+
{ ours: 'line5', theirs: 'line6' },
|
|
318
|
+
]);
|
|
319
|
+
const strategies = [
|
|
320
|
+
{ hunk_index: 0, strategy: 'ours' },
|
|
321
|
+
{ hunk_index: 1, strategy: 'theirs' },
|
|
322
|
+
{ hunk_index: 2, strategy: 'escalate' },
|
|
323
|
+
];
|
|
324
|
+
const result = resolveFileContent(content, strategies, null);
|
|
325
|
+
assert.equal(result.applied, 2);
|
|
326
|
+
assert.equal(result.escalated, 1);
|
|
327
|
+
assert.equal(result.has_unresolved, true);
|
|
328
|
+
});
|
|
329
|
+
|
|
330
|
+
it('handles file with no conflict markers gracefully', () => {
|
|
331
|
+
const content = '// normal file\nconst x = 1;\nmodule.exports = { x };\n';
|
|
332
|
+
const strategies = [];
|
|
333
|
+
const result = resolveFileContent(content, strategies, null);
|
|
334
|
+
assert.equal(result.resolved_content, content);
|
|
335
|
+
assert.equal(result.applied, 0);
|
|
336
|
+
assert.equal(result.escalated, 0);
|
|
337
|
+
assert.equal(result.has_unresolved, false);
|
|
338
|
+
});
|
|
339
|
+
|
|
340
|
+
});
|
|
341
|
+
|
|
342
|
+
// ─── detectSemanticConflicts ─────────────────────────────────────────────────
|
|
343
|
+
|
|
344
|
+
describe('detectSemanticConflicts', () => {
|
|
345
|
+
|
|
346
|
+
it('returns empty array when no files have dual-branch modifications', () => {
|
|
347
|
+
// Test with a non-existent cwd so git commands return nothing useful
|
|
348
|
+
// detectSemanticConflicts checks git log for MERGE_HEAD..HEAD and HEAD..MERGE_HEAD
|
|
349
|
+
// In a non-merge state, these return empty or error, so no warnings
|
|
350
|
+
const result = detectSemanticConflicts('/tmp/nonexistent-dir-' + Date.now(), [], null);
|
|
351
|
+
assert.deepEqual(result, []);
|
|
352
|
+
});
|
|
353
|
+
|
|
354
|
+
it('returns empty array for empty file list', () => {
|
|
355
|
+
const result = detectSemanticConflicts(process.cwd(), [], null);
|
|
356
|
+
assert.deepEqual(result, []);
|
|
357
|
+
});
|
|
358
|
+
|
|
359
|
+
it('includes domain information when plan context available', () => {
|
|
360
|
+
// This test verifies the function signature and output shape
|
|
361
|
+
// Without a real merge state, the function won't find dual-branch modifications
|
|
362
|
+
const planContext = [
|
|
363
|
+
{ task_name: 'Update parser', action_excerpt: 'modify parser logic' },
|
|
364
|
+
];
|
|
365
|
+
const result = detectSemanticConflicts('/tmp/nonexistent-dir-' + Date.now(), ['parser.js'], planContext);
|
|
366
|
+
// No real git repo so no warnings generated, but function handles gracefully
|
|
367
|
+
assert.ok(Array.isArray(result));
|
|
368
|
+
});
|
|
369
|
+
|
|
370
|
+
it('returns risk level based on domain overlap', () => {
|
|
371
|
+
// Verify the output shape when warnings are present
|
|
372
|
+
// We can test this by creating a mock result structure
|
|
373
|
+
// The function itself requires a real merge state to produce warnings
|
|
374
|
+
// Testing the expected shape: { file, domain, ours_changes, theirs_changes, risk }
|
|
375
|
+
const result = detectSemanticConflicts('/tmp/nonexistent-dir-' + Date.now(), [], null);
|
|
376
|
+
assert.ok(Array.isArray(result));
|
|
377
|
+
// Verify it handles gracefully even without real git state
|
|
378
|
+
assert.equal(result.length, 0);
|
|
379
|
+
});
|
|
380
|
+
|
|
381
|
+
});
|
|
382
|
+
|
|
383
|
+
// ─── createLearningContext and mergeLearningContexts ─────────────────────────
|
|
384
|
+
|
|
385
|
+
describe('createLearningContext and mergeLearningContexts', () => {
|
|
386
|
+
|
|
387
|
+
it('creates learning context from resolution results', () => {
|
|
388
|
+
const resolutionResults = [
|
|
389
|
+
{
|
|
390
|
+
file: 'src/config.cjs',
|
|
391
|
+
strategies: [{ strategy: 'ours', confidence: 'HIGH' }],
|
|
392
|
+
result: { applied: 1, escalated: 0 },
|
|
393
|
+
},
|
|
394
|
+
{
|
|
395
|
+
file: 'src/utils.cjs',
|
|
396
|
+
strategies: [{ strategy: 'combined', confidence: 'MEDIUM' }, { strategy: 'theirs', confidence: 'HIGH' }],
|
|
397
|
+
result: { applied: 2, escalated: 0 },
|
|
398
|
+
},
|
|
399
|
+
];
|
|
400
|
+
const ctx = createLearningContext(resolutionResults);
|
|
401
|
+
assert.deepEqual(ctx.files_resolved, ['src/config.cjs', 'src/utils.cjs']);
|
|
402
|
+
assert.equal(ctx.strategies_used.length, 3);
|
|
403
|
+
assert.ok(ctx.domain_changes.config);
|
|
404
|
+
assert.ok(ctx.domain_changes.utils);
|
|
405
|
+
assert.equal(ctx.phase_merges_completed, 1);
|
|
406
|
+
});
|
|
407
|
+
|
|
408
|
+
it('merges two learning contexts preserving all entries', () => {
|
|
409
|
+
const ctx1 = {
|
|
410
|
+
files_resolved: ['a.cjs'],
|
|
411
|
+
strategies_used: [{ file: 'a.cjs', strategy: 'ours' }],
|
|
412
|
+
domain_changes: { a: 'Resolved via ours' },
|
|
413
|
+
phase_merges_completed: 1,
|
|
414
|
+
};
|
|
415
|
+
const ctx2 = {
|
|
416
|
+
files_resolved: ['b.cjs'],
|
|
417
|
+
strategies_used: [{ file: 'b.cjs', strategy: 'theirs' }],
|
|
418
|
+
domain_changes: { b: 'Resolved via theirs' },
|
|
419
|
+
phase_merges_completed: 1,
|
|
420
|
+
};
|
|
421
|
+
const merged = mergeLearningContexts(ctx1, ctx2);
|
|
422
|
+
assert.deepEqual(merged.files_resolved, ['a.cjs', 'b.cjs']);
|
|
423
|
+
assert.equal(merged.strategies_used.length, 2);
|
|
424
|
+
assert.ok(merged.domain_changes.a);
|
|
425
|
+
assert.ok(merged.domain_changes.b);
|
|
426
|
+
assert.equal(merged.phase_merges_completed, 2);
|
|
427
|
+
});
|
|
428
|
+
|
|
429
|
+
it('handles empty existing context on first merge', () => {
|
|
430
|
+
const newCtx = {
|
|
431
|
+
files_resolved: ['first.cjs'],
|
|
432
|
+
strategies_used: [{ file: 'first.cjs', strategy: 'combined' }],
|
|
433
|
+
domain_changes: { first: 'Resolved via combined' },
|
|
434
|
+
phase_merges_completed: 1,
|
|
435
|
+
};
|
|
436
|
+
const merged = mergeLearningContexts(null, newCtx);
|
|
437
|
+
assert.deepEqual(merged.files_resolved, ['first.cjs']);
|
|
438
|
+
assert.equal(merged.strategies_used.length, 1);
|
|
439
|
+
assert.equal(merged.phase_merges_completed, 1);
|
|
440
|
+
});
|
|
441
|
+
|
|
442
|
+
it('accumulates across 3 sequential merges', () => {
|
|
443
|
+
const ctx1 = createLearningContext([{ file: 'a.cjs', strategies: [{ strategy: 'ours' }], result: {} }]);
|
|
444
|
+
const ctx2 = createLearningContext([{ file: 'b.cjs', strategies: [{ strategy: 'theirs' }], result: {} }]);
|
|
445
|
+
const ctx3 = createLearningContext([{ file: 'c.cjs', strategies: [{ strategy: 'combined' }], result: {} }]);
|
|
446
|
+
|
|
447
|
+
let acc = mergeLearningContexts(null, ctx1);
|
|
448
|
+
acc = mergeLearningContexts(acc, ctx2);
|
|
449
|
+
acc = mergeLearningContexts(acc, ctx3);
|
|
450
|
+
|
|
451
|
+
assert.deepEqual(acc.files_resolved, ['a.cjs', 'b.cjs', 'c.cjs']);
|
|
452
|
+
assert.equal(acc.strategies_used.length, 3);
|
|
453
|
+
assert.equal(acc.phase_merges_completed, 3);
|
|
454
|
+
assert.ok(acc.domain_changes.a);
|
|
455
|
+
assert.ok(acc.domain_changes.b);
|
|
456
|
+
assert.ok(acc.domain_changes.c);
|
|
457
|
+
});
|
|
458
|
+
|
|
459
|
+
});
|
|
460
|
+
|
|
461
|
+
// ─── buildResolutionReport ───────────────────────────────────────────────────
|
|
462
|
+
|
|
463
|
+
describe('buildResolutionReport', () => {
|
|
464
|
+
|
|
465
|
+
const sampleFileResults = [
|
|
466
|
+
{
|
|
467
|
+
file: 'src/config.cjs',
|
|
468
|
+
hunks: [{
|
|
469
|
+
type: 'ADDITIVE',
|
|
470
|
+
start_line: 2,
|
|
471
|
+
end_line: 6,
|
|
472
|
+
ours: '',
|
|
473
|
+
theirs: 'const newConfig = true;',
|
|
474
|
+
}],
|
|
475
|
+
strategies: [{
|
|
476
|
+
hunk_index: 0,
|
|
477
|
+
strategy: 'theirs',
|
|
478
|
+
confidence: 'HIGH',
|
|
479
|
+
reasoning: 'Additive hunk: theirs adds new content',
|
|
480
|
+
}],
|
|
481
|
+
result: { applied: 1, escalated: 0 },
|
|
482
|
+
},
|
|
483
|
+
{
|
|
484
|
+
file: 'src/utils.cjs',
|
|
485
|
+
hunks: [{
|
|
486
|
+
type: 'DIVERGENT',
|
|
487
|
+
start_line: 10,
|
|
488
|
+
end_line: 14,
|
|
489
|
+
ours: 'const val = 1;',
|
|
490
|
+
theirs: 'const val = 2;',
|
|
491
|
+
}],
|
|
492
|
+
strategies: [{
|
|
493
|
+
hunk_index: 0,
|
|
494
|
+
strategy: 'escalate',
|
|
495
|
+
confidence: 'LOW',
|
|
496
|
+
reasoning: 'Divergent hunk: no plan context',
|
|
497
|
+
}],
|
|
498
|
+
result: { applied: 0, escalated: 1 },
|
|
499
|
+
},
|
|
500
|
+
];
|
|
501
|
+
|
|
502
|
+
const sampleMetadata = {
|
|
503
|
+
branches: { ours: 'main', theirs: 'feature-x' },
|
|
504
|
+
phase: '01-test',
|
|
505
|
+
timestamp: '2026-02-27T00:00:00Z',
|
|
506
|
+
semantic_warnings: [
|
|
507
|
+
{ file: 'src/shared.cjs', domain: 'shared', ours_changes: 'add helper', theirs_changes: 'modify helper', risk: 'warning' },
|
|
508
|
+
],
|
|
509
|
+
};
|
|
510
|
+
|
|
511
|
+
it('produces valid markdown with all sections', () => {
|
|
512
|
+
const report = buildResolutionReport(sampleFileResults, sampleMetadata);
|
|
513
|
+
assert.ok(report.includes('# Conflict Resolution Report'));
|
|
514
|
+
assert.ok(report.includes('## Resolved Conflicts'));
|
|
515
|
+
assert.ok(report.includes('## Semantic Warnings'));
|
|
516
|
+
assert.ok(report.includes('## Summary'));
|
|
517
|
+
});
|
|
518
|
+
|
|
519
|
+
it('includes per-file detail with truncated before/after snippets', () => {
|
|
520
|
+
const report = buildResolutionReport(sampleFileResults, sampleMetadata);
|
|
521
|
+
assert.ok(report.includes('src/config.cjs'));
|
|
522
|
+
assert.ok(report.includes('src/utils.cjs'));
|
|
523
|
+
// Should include ours/theirs side snippets
|
|
524
|
+
assert.ok(report.includes('Ours side (truncated)') || report.includes('Theirs side (truncated)'));
|
|
525
|
+
});
|
|
526
|
+
|
|
527
|
+
it('includes confidence breakdown in summary', () => {
|
|
528
|
+
const report = buildResolutionReport(sampleFileResults, sampleMetadata);
|
|
529
|
+
// Should have confidence count table
|
|
530
|
+
assert.ok(report.includes('| HIGH |'));
|
|
531
|
+
assert.ok(report.includes('| MEDIUM |'));
|
|
532
|
+
assert.ok(report.includes('| LOW |'));
|
|
533
|
+
});
|
|
534
|
+
|
|
535
|
+
it('includes semantic warnings section', () => {
|
|
536
|
+
const report = buildResolutionReport(sampleFileResults, sampleMetadata);
|
|
537
|
+
assert.ok(report.includes('src/shared.cjs'));
|
|
538
|
+
assert.ok(report.includes('warning'));
|
|
539
|
+
assert.ok(report.includes('shared'));
|
|
540
|
+
});
|
|
541
|
+
|
|
542
|
+
it('shows no semantic warnings message when array is empty', () => {
|
|
543
|
+
const metaNoWarnings = { ...sampleMetadata, semantic_warnings: [] };
|
|
544
|
+
const report = buildResolutionReport(sampleFileResults, metaNoWarnings);
|
|
545
|
+
assert.ok(report.includes('No semantic conflicts detected'));
|
|
546
|
+
});
|
|
547
|
+
|
|
548
|
+
it('includes overall assessment based on confidence levels', () => {
|
|
549
|
+
const report = buildResolutionReport(sampleFileResults, sampleMetadata);
|
|
550
|
+
// Has LOW confidence, so assessment should recommend review
|
|
551
|
+
assert.ok(report.includes('Manual review recommended') || report.includes('LOW confidence'));
|
|
552
|
+
});
|
|
553
|
+
|
|
554
|
+
});
|