@mergesignal/shared 0.4.3 → 0.5.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/dist/actionsStepSummary.d.ts +1 -22
- package/dist/actionsStepSummary.d.ts.map +1 -1
- package/dist/actionsStepSummary.js +19 -716
- package/dist/actionsStepSummary.test.js +34 -329
- package/dist/assessmentLabels.d.ts +6 -0
- package/dist/assessmentLabels.d.ts.map +1 -0
- package/dist/assessmentLabels.js +33 -0
- package/dist/assessmentProjection.d.ts +12 -0
- package/dist/assessmentProjection.d.ts.map +1 -0
- package/dist/assessmentProjection.js +100 -0
- package/dist/assessmentSchema.d.ts +155 -0
- package/dist/assessmentSchema.d.ts.map +1 -0
- package/dist/assessmentSchema.js +110 -0
- package/dist/cardObservationCatalog.d.ts +2 -0
- package/dist/cardObservationCatalog.d.ts.map +1 -1
- package/dist/cardObservationCatalog.js +47 -1
- package/dist/engineWireRegression.test.js +22 -2
- package/dist/fixtures/assessmentFixtures.d.ts +13 -0
- package/dist/fixtures/assessmentFixtures.d.ts.map +1 -0
- package/dist/fixtures/assessmentFixtures.js +164 -0
- package/dist/formatCardExposureDisplay.d.ts +0 -4
- package/dist/formatCardExposureDisplay.d.ts.map +1 -1
- package/dist/formatCardExposureDisplay.js +0 -15
- package/dist/formatInsight.d.ts +3 -2
- package/dist/formatInsight.d.ts.map +1 -1
- package/dist/formatInsight.js +26 -1
- package/dist/index.d.ts +7 -11
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -11
- package/dist/narrativeParity.test.js +4 -34
- package/dist/presentGitHubPrComment.d.ts +1 -3
- package/dist/presentGitHubPrComment.d.ts.map +1 -1
- package/dist/presentGitHubPrComment.js +0 -17
- package/dist/presentation/compose/narrativeChannels.d.ts.map +1 -1
- package/dist/presentation/compose/narrativeChannels.js +13 -43
- package/dist/presentation/compose/narrativeCompose.d.ts.map +1 -1
- package/dist/presentation/compose/narrativeCompose.js +2 -5
- package/dist/presentation/dto/assessmentPresentationFields.d.ts +13 -0
- package/dist/presentation/dto/assessmentPresentationFields.d.ts.map +1 -0
- package/dist/presentation/dto/assessmentPresentationFields.js +1 -0
- package/dist/presentation/dto/dashboardCardPresentation.d.ts +2 -1
- package/dist/presentation/dto/dashboardCardPresentation.d.ts.map +1 -1
- package/dist/presentation/dto/githubAndCliPresentation.d.ts +4 -3
- package/dist/presentation/dto/githubAndCliPresentation.d.ts.map +1 -1
- package/dist/presentation/dto/scanDetailsPresentation.d.ts +2 -1
- package/dist/presentation/dto/scanDetailsPresentation.d.ts.map +1 -1
- package/dist/presentation/fixtures/dashboardCardGolden.test.js +21 -14
- package/dist/presentation/fixtures/presentationPersonaFixtures.d.ts.map +1 -1
- package/dist/presentation/fixtures/presentationPersonaFixtures.js +31 -24
- package/dist/presentation/fixtures/scanResultFixtures.d.ts.map +1 -1
- package/dist/presentation/fixtures/scanResultFixtures.js +14 -3
- package/dist/presentation/index.d.ts +0 -1
- package/dist/presentation/index.d.ts.map +1 -1
- package/dist/presentation/index.js +0 -1
- package/dist/presentation/orchestration/buildScanCardPresentation.d.ts.map +1 -1
- package/dist/presentation/orchestration/buildScanCardPresentation.js +8 -3
- package/dist/presentation/orchestration/buildScanPresentationBundle.d.ts +1 -1
- package/dist/presentation/orchestration/buildScanPresentationBundle.d.ts.map +1 -1
- package/dist/presentation/orchestration/buildScanPresentationBundle.js +12 -10
- package/dist/presentation/orchestration/scanPresentationBundle.d.ts +8 -3
- package/dist/presentation/orchestration/scanPresentationBundle.d.ts.map +1 -1
- package/dist/presentation/presentationPersonas.test.js +6 -6
- package/dist/presentation/presenters/presentCliScanSummary.d.ts.map +1 -1
- package/dist/presentation/presenters/presentCliScanSummary.js +2 -0
- package/dist/presentation/presenters/presentDashboardCard.d.ts.map +1 -1
- package/dist/presentation/presenters/presentDashboardCard.js +2 -0
- package/dist/presentation/presenters/presentGitHubCheckRun.d.ts.map +1 -1
- package/dist/presentation/presenters/presentGitHubCheckRun.js +2 -0
- package/dist/presentation/presenters/presentGitHubPrComment.d.ts.map +1 -1
- package/dist/presentation/presenters/presentGitHubPrComment.js +15 -21
- package/dist/presentation/presenters/presentScanDetails.d.ts.map +1 -1
- package/dist/presentation/presenters/presentScanDetails.js +52 -129
- package/dist/presentation/profile/buildProfileFromAssessment.d.ts +5 -0
- package/dist/presentation/profile/buildProfileFromAssessment.d.ts.map +1 -0
- package/dist/presentation/profile/buildProfileFromAssessment.js +58 -0
- package/dist/presentation/projectAssessmentFields.d.ts +4 -0
- package/dist/presentation/projectAssessmentFields.d.ts.map +1 -0
- package/dist/presentation/projectAssessmentFields.js +13 -0
- package/dist/presentation/surfaceParity.test.d.ts +2 -0
- package/dist/presentation/surfaceParity.test.d.ts.map +1 -0
- package/dist/presentation/surfaceParity.test.js +74 -0
- package/dist/productMessaging.d.ts +4 -4
- package/dist/productMessaging.d.ts.map +1 -1
- package/dist/productMessaging.js +4 -4
- package/dist/productMessaging.test.js +2 -2
- package/dist/repoIntelligenceSchema.d.ts +2 -2
- package/dist/resolvePipelineStatus.d.ts +15 -0
- package/dist/resolvePipelineStatus.d.ts.map +1 -0
- package/dist/resolvePipelineStatus.js +37 -0
- package/dist/scanCardPresentationState.d.ts +4 -0
- package/dist/scanCardPresentationState.d.ts.map +1 -0
- package/dist/scanCardPresentationState.js +4 -0
- package/dist/{scanDetailViewModel.d.ts → scanDetailViewModelTypes.d.ts} +60 -32
- package/dist/scanDetailViewModelTypes.d.ts.map +1 -0
- package/dist/scanDetailViewModelTypes.js +4 -0
- package/dist/scanResultSchema.d.ts +75 -2
- package/dist/scanResultSchema.d.ts.map +1 -1
- package/dist/scanResultSchema.js +4 -2
- package/dist/scanResultSchema.test.js +16 -0
- package/dist/trustedScanGuards.test.js +7 -0
- package/dist/types.d.ts +3 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/dist/collectNarrativeWhyBullets.d.ts +0 -12
- package/dist/collectNarrativeWhyBullets.d.ts.map +0 -1
- package/dist/collectNarrativeWhyBullets.js +0 -104
- package/dist/deriveCardDisplaySummary.d.ts +0 -16
- package/dist/deriveCardDisplaySummary.d.ts.map +0 -1
- package/dist/deriveCardDisplaySummary.js +0 -56
- package/dist/deriveCardDisplaySummary.test.d.ts +0 -2
- package/dist/deriveCardDisplaySummary.test.d.ts.map +0 -1
- package/dist/deriveCardDisplaySummary.test.js +0 -89
- package/dist/deriveCardOperationalObservations.d.ts +0 -19
- package/dist/deriveCardOperationalObservations.d.ts.map +0 -1
- package/dist/deriveCardOperationalObservations.js +0 -180
- package/dist/deriveCardOperationalObservations.test.d.ts +0 -2
- package/dist/deriveCardOperationalObservations.test.d.ts.map +0 -1
- package/dist/deriveCardOperationalObservations.test.js +0 -268
- package/dist/deriveRiskScoreSummary.d.ts +0 -33
- package/dist/deriveRiskScoreSummary.d.ts.map +0 -1
- package/dist/deriveRiskScoreSummary.js +0 -90
- package/dist/deriveRiskScoreSummary.test.d.ts +0 -2
- package/dist/deriveRiskScoreSummary.test.d.ts.map +0 -1
- package/dist/deriveRiskScoreSummary.test.js +0 -47
- package/dist/deriveScanDetailRecommendations.d.ts +0 -63
- package/dist/deriveScanDetailRecommendations.d.ts.map +0 -1
- package/dist/deriveScanDetailRecommendations.js +0 -725
- package/dist/deriveScanDetailRecommendations.test.d.ts +0 -2
- package/dist/deriveScanDetailRecommendations.test.d.ts.map +0 -1
- package/dist/deriveScanDetailRecommendations.test.js +0 -181
- package/dist/deriveScanSummaryText.d.ts +0 -7
- package/dist/deriveScanSummaryText.d.ts.map +0 -1
- package/dist/deriveScanSummaryText.js +0 -24
- package/dist/deriveScanSummaryText.test.d.ts +0 -2
- package/dist/deriveScanSummaryText.test.d.ts.map +0 -1
- package/dist/deriveScanSummaryText.test.js +0 -77
- package/dist/formatCardEvidenceCounts.d.ts +0 -7
- package/dist/formatCardEvidenceCounts.d.ts.map +0 -1
- package/dist/formatCardEvidenceCounts.js +0 -19
- package/dist/prCheckRunPresentation.d.ts +0 -68
- package/dist/prCheckRunPresentation.d.ts.map +0 -1
- package/dist/prCheckRunPresentation.js +0 -319
- package/dist/prCheckRunPresentation.test.d.ts +0 -2
- package/dist/prCheckRunPresentation.test.d.ts.map +0 -1
- package/dist/prCheckRunPresentation.test.js +0 -278
- package/dist/presentation/intent/derivePresentationInterpretation.d.ts +0 -4
- package/dist/presentation/intent/derivePresentationInterpretation.d.ts.map +0 -1
- package/dist/presentation/intent/derivePresentationInterpretation.js +0 -202
- package/dist/presentation/intent/formatPresentationCopy.d.ts +0 -8
- package/dist/presentation/intent/formatPresentationCopy.d.ts.map +0 -1
- package/dist/presentation/intent/formatPresentationCopy.js +0 -140
- package/dist/presentation/intent/presentationIntent.test.d.ts +0 -2
- package/dist/presentation/intent/presentationIntent.test.d.ts.map +0 -1
- package/dist/presentation/intent/presentationIntent.test.js +0 -29
- package/dist/presentation/intent/verificationFocusLabels.d.ts +0 -2
- package/dist/presentation/intent/verificationFocusLabels.d.ts.map +0 -1
- package/dist/presentation/intent/verificationFocusLabels.js +0 -45
- package/dist/presentation/profile/derivePresentationProfile.d.ts +0 -12
- package/dist/presentation/profile/derivePresentationProfile.d.ts.map +0 -1
- package/dist/presentation/profile/derivePresentationProfile.js +0 -85
- package/dist/scanCardSummary.d.ts +0 -58
- package/dist/scanCardSummary.d.ts.map +0 -1
- package/dist/scanCardSummary.js +0 -146
- package/dist/scanCardSummary.test.d.ts +0 -2
- package/dist/scanCardSummary.test.d.ts.map +0 -1
- package/dist/scanCardSummary.test.js +0 -234
- package/dist/scanDetailViewModel.d.ts.map +0 -1
- package/dist/scanDetailViewModel.js +0 -636
- package/dist/scanDetailViewModel.test.d.ts +0 -2
- package/dist/scanDetailViewModel.test.d.ts.map +0 -1
- package/dist/scanDetailViewModel.test.js +0 -530
|
@@ -1,268 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from "vitest";
|
|
2
|
-
import { CARD_OBSERVATION_CATALOG, containsImperativeOrActionLanguage, containsTelemetryOrDigits, isCatalogPhrase, isGenericObservation, mapRecommendationToCatalogPhrase, mapTextToCatalogPhrase, validateCatalogIntegrity, } from "./cardObservationCatalog.js";
|
|
3
|
-
import { deriveCardOperationalObservations } from "./deriveCardOperationalObservations.js";
|
|
4
|
-
const baseResult = {
|
|
5
|
-
totalScore: 10,
|
|
6
|
-
layerScores: {
|
|
7
|
-
security: 1,
|
|
8
|
-
maintainability: 2,
|
|
9
|
-
ecosystem: 3,
|
|
10
|
-
upgradeImpact: 4,
|
|
11
|
-
},
|
|
12
|
-
findings: [],
|
|
13
|
-
generatedAt: "2026-01-01T00:00:00.000Z",
|
|
14
|
-
};
|
|
15
|
-
describe("cardObservationCatalog", () => {
|
|
16
|
-
it("validates catalog integrity", () => {
|
|
17
|
-
expect(() => validateCatalogIntegrity()).not.toThrow();
|
|
18
|
-
});
|
|
19
|
-
it("keeps all catalog phrases within length and guardrails", () => {
|
|
20
|
-
for (const phrase of CARD_OBSERVATION_CATALOG) {
|
|
21
|
-
expect(isCatalogPhrase(phrase)).toBe(true);
|
|
22
|
-
expect(containsTelemetryOrDigits(phrase)).toBe(false);
|
|
23
|
-
expect(containsImperativeOrActionLanguage(phrase)).toBe(false);
|
|
24
|
-
expect(isGenericObservation(phrase)).toBe(false);
|
|
25
|
-
expect(phrase.length).toBeLessThanOrEqual(48);
|
|
26
|
-
}
|
|
27
|
-
});
|
|
28
|
-
it("maps recommendation imperatives to detection phrases", () => {
|
|
29
|
-
const mapped = mapRecommendationToCatalogPhrase({
|
|
30
|
-
id: "rec-1",
|
|
31
|
-
title: "Reduce duplicate dependency versions",
|
|
32
|
-
rationale: "Overlapping semver ranges on runtime boundary",
|
|
33
|
-
impact: "high",
|
|
34
|
-
});
|
|
35
|
-
expect(mapped?.phrase).toBe("Duplicate dependency versions detected");
|
|
36
|
-
});
|
|
37
|
-
it("maps graph.duplicates tokens to duplicate versions phrase", () => {
|
|
38
|
-
const mapped = mapTextToCatalogPhrase("graph.duplicates on runtime boundary");
|
|
39
|
-
expect(mapped?.phrase).toBe("Duplicate dependency versions detected");
|
|
40
|
-
});
|
|
41
|
-
it("rejects generic narration", () => {
|
|
42
|
-
expect(isGenericObservation("No high-confidence merge risks")).toBe(true);
|
|
43
|
-
expect(isGenericObservation("dependency concerns detected")).toBe(true);
|
|
44
|
-
});
|
|
45
|
-
});
|
|
46
|
-
describe("deriveCardOperationalObservations", () => {
|
|
47
|
-
it("returns silence on primary path when no mappable signals", () => {
|
|
48
|
-
const result = deriveCardOperationalObservations({
|
|
49
|
-
...baseResult,
|
|
50
|
-
decision: {
|
|
51
|
-
recommendation: "safe",
|
|
52
|
-
confidence: "high",
|
|
53
|
-
reasoning: [
|
|
54
|
-
"No high-confidence merge risks from this PR dependency change",
|
|
55
|
-
],
|
|
56
|
-
},
|
|
57
|
-
}, { mergePosture: "safe", hasFullResult: true });
|
|
58
|
-
expect(result.operationalObservations).toEqual([]);
|
|
59
|
-
expect(result.supportingLine).toBeNull();
|
|
60
|
-
});
|
|
61
|
-
it("surfaces catalog phrase from explain.reasons instead of generic reasoning", () => {
|
|
62
|
-
const result = deriveCardOperationalObservations({
|
|
63
|
-
...baseResult,
|
|
64
|
-
totalScore: 55,
|
|
65
|
-
decision: {
|
|
66
|
-
recommendation: "needs_review",
|
|
67
|
-
confidence: "medium",
|
|
68
|
-
reasoning: ["Potential runtime impact detected"],
|
|
69
|
-
},
|
|
70
|
-
explain: {
|
|
71
|
-
reasons: [
|
|
72
|
-
{
|
|
73
|
-
id: "graph.transitive.1",
|
|
74
|
-
layer: "ecosystem",
|
|
75
|
-
title: "graph.transitive volume cluster",
|
|
76
|
-
scoreImpact: 18,
|
|
77
|
-
},
|
|
78
|
-
],
|
|
79
|
-
},
|
|
80
|
-
}, { mergePosture: "needs_review", hasFullResult: true });
|
|
81
|
-
expect(result.operationalObservations).toContain("High transitive dependency volume");
|
|
82
|
-
expect(result.operationalObservations.some((o) => /merge risk|runtime impact/i.test(o))).toBe(false);
|
|
83
|
-
});
|
|
84
|
-
it("maps duplicate signal from recommendation without leaking imperative title", () => {
|
|
85
|
-
const result = deriveCardOperationalObservations({
|
|
86
|
-
...baseResult,
|
|
87
|
-
recommendations: [
|
|
88
|
-
{
|
|
89
|
-
id: "rec-dup",
|
|
90
|
-
title: "Reduce duplicate dependency versions",
|
|
91
|
-
rationale: "Multiple semver majors on shared packages",
|
|
92
|
-
impact: "high",
|
|
93
|
-
priorityScore: 90,
|
|
94
|
-
},
|
|
95
|
-
],
|
|
96
|
-
}, { mergePosture: "needs_review", hasFullResult: true });
|
|
97
|
-
expect(result.operationalObservations).toEqual([
|
|
98
|
-
"Duplicate dependency versions detected",
|
|
99
|
-
]);
|
|
100
|
-
expect(result.operationalObservations.some((o) => /^reduce/i.test(o))).toBe(false);
|
|
101
|
-
});
|
|
102
|
-
it("caps at three distinct catalog phrases on fat scans", () => {
|
|
103
|
-
const fat = {
|
|
104
|
-
...baseResult,
|
|
105
|
-
totalScore: 72,
|
|
106
|
-
recommendations: [
|
|
107
|
-
{
|
|
108
|
-
id: "r1",
|
|
109
|
-
title: "Reduce duplicate dependency versions",
|
|
110
|
-
rationale: "semver overlap",
|
|
111
|
-
impact: "high",
|
|
112
|
-
priorityScore: 95,
|
|
113
|
-
},
|
|
114
|
-
{
|
|
115
|
-
id: "r2",
|
|
116
|
-
title: "Review transitive dependency surface",
|
|
117
|
-
rationale: "graph.transitive volume",
|
|
118
|
-
impact: "high",
|
|
119
|
-
priorityScore: 90,
|
|
120
|
-
},
|
|
121
|
-
],
|
|
122
|
-
explain: {
|
|
123
|
-
reasons: [
|
|
124
|
-
{
|
|
125
|
-
id: "g1",
|
|
126
|
-
layer: "security",
|
|
127
|
-
title: "graph.vulnerable packages",
|
|
128
|
-
scoreImpact: 20,
|
|
129
|
-
},
|
|
130
|
-
{
|
|
131
|
-
id: "g2",
|
|
132
|
-
layer: "maintainability",
|
|
133
|
-
title: "Stale releases on multiple direct dependencies",
|
|
134
|
-
scoreImpact: 15,
|
|
135
|
-
},
|
|
136
|
-
],
|
|
137
|
-
},
|
|
138
|
-
graphInsights: {
|
|
139
|
-
maxDepth: 9,
|
|
140
|
-
nodes: 1500,
|
|
141
|
-
edges: 4000,
|
|
142
|
-
vulnerable: [
|
|
143
|
-
{
|
|
144
|
-
kind: "vulnerable",
|
|
145
|
-
packageName: "lodash",
|
|
146
|
-
direct: false,
|
|
147
|
-
depth: 3,
|
|
148
|
-
},
|
|
149
|
-
],
|
|
150
|
-
hotspots: Array.from({ length: 5 }, (_, i) => ({
|
|
151
|
-
kind: "hotspot",
|
|
152
|
-
packageName: `pkg-${i}`,
|
|
153
|
-
direct: true,
|
|
154
|
-
depth: 1,
|
|
155
|
-
})),
|
|
156
|
-
},
|
|
157
|
-
};
|
|
158
|
-
const result = deriveCardOperationalObservations(fat, {
|
|
159
|
-
mergePosture: "risky",
|
|
160
|
-
hasFullResult: true,
|
|
161
|
-
max: 3,
|
|
162
|
-
});
|
|
163
|
-
expect(result.operationalObservations.length).toBeLessThanOrEqual(3);
|
|
164
|
-
for (const phrase of result.operationalObservations) {
|
|
165
|
-
expect(isCatalogPhrase(phrase)).toBe(true);
|
|
166
|
-
expect(containsTelemetryOrDigits(phrase)).toBe(false);
|
|
167
|
-
expect(containsImperativeOrActionLanguage(phrase)).toBe(false);
|
|
168
|
-
}
|
|
169
|
-
expect(result.supportingLine).toBeNull();
|
|
170
|
-
});
|
|
171
|
-
it("prefers one to two observations when one family dominates", () => {
|
|
172
|
-
const result = deriveCardOperationalObservations({
|
|
173
|
-
...baseResult,
|
|
174
|
-
explain: {
|
|
175
|
-
reasons: [
|
|
176
|
-
{
|
|
177
|
-
id: "t1",
|
|
178
|
-
layer: "ecosystem",
|
|
179
|
-
title: "graph.transitive volume cluster 1",
|
|
180
|
-
scoreImpact: 30,
|
|
181
|
-
},
|
|
182
|
-
{
|
|
183
|
-
id: "t2",
|
|
184
|
-
layer: "ecosystem",
|
|
185
|
-
title: "graph.transitive volume cluster 2",
|
|
186
|
-
scoreImpact: 25,
|
|
187
|
-
},
|
|
188
|
-
{
|
|
189
|
-
id: "t3",
|
|
190
|
-
layer: "ecosystem",
|
|
191
|
-
title: "graph.transitive volume cluster 3",
|
|
192
|
-
scoreImpact: 20,
|
|
193
|
-
},
|
|
194
|
-
],
|
|
195
|
-
},
|
|
196
|
-
}, { mergePosture: "needs_review", hasFullResult: true });
|
|
197
|
-
expect(result.operationalObservations).toEqual([
|
|
198
|
-
"High transitive dependency volume",
|
|
199
|
-
]);
|
|
200
|
-
});
|
|
201
|
-
it("omits supporting line when three observations are shown", () => {
|
|
202
|
-
const result = deriveCardOperationalObservations({
|
|
203
|
-
...baseResult,
|
|
204
|
-
recommendations: [
|
|
205
|
-
{
|
|
206
|
-
id: "r1",
|
|
207
|
-
title: "Reduce duplicate dependency versions",
|
|
208
|
-
rationale: "dup",
|
|
209
|
-
impact: "high",
|
|
210
|
-
priorityScore: 95,
|
|
211
|
-
},
|
|
212
|
-
],
|
|
213
|
-
explain: {
|
|
214
|
-
reasons: [
|
|
215
|
-
{
|
|
216
|
-
id: "e1",
|
|
217
|
-
layer: "security",
|
|
218
|
-
title: "graph.vulnerable",
|
|
219
|
-
scoreImpact: 20,
|
|
220
|
-
},
|
|
221
|
-
{
|
|
222
|
-
id: "e2",
|
|
223
|
-
layer: "upgradeImpact",
|
|
224
|
-
title: "Large upgrade blast radius",
|
|
225
|
-
scoreImpact: 18,
|
|
226
|
-
},
|
|
227
|
-
],
|
|
228
|
-
},
|
|
229
|
-
}, { mergePosture: "risky", hasFullResult: true });
|
|
230
|
-
if (result.operationalObservations.length === 3) {
|
|
231
|
-
expect(result.supportingLine).toBeNull();
|
|
232
|
-
}
|
|
233
|
-
});
|
|
234
|
-
it("allows supporting line only with exactly one observation", () => {
|
|
235
|
-
const result = deriveCardOperationalObservations({
|
|
236
|
-
...baseResult,
|
|
237
|
-
recommendations: [
|
|
238
|
-
{
|
|
239
|
-
id: "r1",
|
|
240
|
-
title: "Reduce duplicate dependency versions",
|
|
241
|
-
rationale: "dup",
|
|
242
|
-
impact: "high",
|
|
243
|
-
priorityScore: 95,
|
|
244
|
-
},
|
|
245
|
-
],
|
|
246
|
-
explain: {
|
|
247
|
-
reasons: [
|
|
248
|
-
{
|
|
249
|
-
id: "e1",
|
|
250
|
-
layer: "security",
|
|
251
|
-
title: "graph.vulnerable packages in tree",
|
|
252
|
-
scoreImpact: 10,
|
|
253
|
-
},
|
|
254
|
-
],
|
|
255
|
-
},
|
|
256
|
-
}, { mergePosture: "needs_review", hasFullResult: true });
|
|
257
|
-
if (result.operationalObservations.length === 1) {
|
|
258
|
-
expect(result.supportingLine).toBe("Vulnerable transitive packages detected");
|
|
259
|
-
}
|
|
260
|
-
});
|
|
261
|
-
it("returns silence on denormalized path without signals", () => {
|
|
262
|
-
const result = deriveCardOperationalObservations(null, {
|
|
263
|
-
mergePosture: "safe",
|
|
264
|
-
hasFullResult: false,
|
|
265
|
-
});
|
|
266
|
-
expect(result.operationalObservations).toEqual([]);
|
|
267
|
-
});
|
|
268
|
-
});
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
import type { ScanResult, ScoreLayer } from "./types.js";
|
|
2
|
-
export declare const SCAN_DETAIL_RISK_BAND_MODERATE_MIN = 40;
|
|
3
|
-
export declare const SCAN_DETAIL_RISK_BAND_HIGH_MIN = 80;
|
|
4
|
-
export type ScanDetailOverallRiskBand = "low" | "moderate" | "high";
|
|
5
|
-
export type ScanDetailLayerConcernLevel = "low" | "medium" | "high";
|
|
6
|
-
export type ScanDetailSignalLayer = {
|
|
7
|
-
layer: ScoreLayer;
|
|
8
|
-
label: string;
|
|
9
|
-
score: number;
|
|
10
|
-
concernLevel: ScanDetailLayerConcernLevel;
|
|
11
|
-
concernLabel: string;
|
|
12
|
-
};
|
|
13
|
-
/** @deprecated Use ScanDetailSignalLayer */
|
|
14
|
-
export type ScanDetailRiskLayer = ScanDetailSignalLayer;
|
|
15
|
-
export type RiskScoreGaugeModel = {
|
|
16
|
-
fillPercent: number;
|
|
17
|
-
band: ScanDetailOverallRiskBand;
|
|
18
|
-
ariaLabel: string;
|
|
19
|
-
};
|
|
20
|
-
export type ScanDetailSignalSummary = {
|
|
21
|
-
score: number;
|
|
22
|
-
overallBand: ScanDetailOverallRiskBand;
|
|
23
|
-
overallLabel: string;
|
|
24
|
-
gauge: RiskScoreGaugeModel;
|
|
25
|
-
layers: ScanDetailSignalLayer[];
|
|
26
|
-
};
|
|
27
|
-
/** @deprecated Use ScanDetailSignalSummary */
|
|
28
|
-
export type ScanDetailRiskSummary = ScanDetailSignalSummary;
|
|
29
|
-
export declare function deriveOverallRiskBand(score: number | null | undefined): ScanDetailOverallRiskBand;
|
|
30
|
-
export declare function overallSignalBandLabel(band: ScanDetailOverallRiskBand): string;
|
|
31
|
-
export declare function deriveRiskScoreGauge(score: number, band: ScanDetailOverallRiskBand): RiskScoreGaugeModel;
|
|
32
|
-
export declare function deriveSignalSummary(result: ScanResult): ScanDetailSignalSummary | null;
|
|
33
|
-
//# sourceMappingURL=deriveRiskScoreSummary.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"deriveRiskScoreSummary.d.ts","sourceRoot":"","sources":["../src/deriveRiskScoreSummary.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAEzD,eAAO,MAAM,kCAAkC,KAAK,CAAC;AACrD,eAAO,MAAM,8BAA8B,KAAK,CAAC;AAgBjD,MAAM,MAAM,yBAAyB,GAAG,KAAK,GAAG,UAAU,GAAG,MAAM,CAAC;AACpE,MAAM,MAAM,2BAA2B,GAAG,KAAK,GAAG,QAAQ,GAAG,MAAM,CAAC;AAEpE,MAAM,MAAM,qBAAqB,GAAG;IAClC,KAAK,EAAE,UAAU,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,EAAE,2BAA2B,CAAC;IAC1C,YAAY,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF,4CAA4C;AAC5C,MAAM,MAAM,mBAAmB,GAAG,qBAAqB,CAAC;AAExD,MAAM,MAAM,mBAAmB,GAAG;IAChC,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,yBAAyB,CAAC;IAChC,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,uBAAuB,GAAG;IACpC,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,yBAAyB,CAAC;IACvC,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,mBAAmB,CAAC;IAC3B,MAAM,EAAE,qBAAqB,EAAE,CAAC;CACjC,CAAC;AAEF,8CAA8C;AAC9C,MAAM,MAAM,qBAAqB,GAAG,uBAAuB,CAAC;AAO5D,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAC/B,yBAAyB,CAM3B;AAED,wBAAgB,sBAAsB,CACpC,IAAI,EAAE,yBAAyB,GAC9B,MAAM,CAKR;AAgBD,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,yBAAyB,GAC9B,mBAAmB,CASrB;AAED,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,UAAU,GACjB,uBAAuB,GAAG,IAAI,CAoChC"}
|
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
import { layerRiskBandLabel } from "./actionsStepSummary.js";
|
|
2
|
-
import { scanSurfaceCopy } from "./scanSurfaceCopy.js";
|
|
3
|
-
export const SCAN_DETAIL_RISK_BAND_MODERATE_MIN = 40;
|
|
4
|
-
export const SCAN_DETAIL_RISK_BAND_HIGH_MIN = 80;
|
|
5
|
-
const LAYER_ORDER = [
|
|
6
|
-
"security",
|
|
7
|
-
"maintainability",
|
|
8
|
-
"ecosystem",
|
|
9
|
-
"upgradeImpact",
|
|
10
|
-
];
|
|
11
|
-
const LAYER_LABEL = {
|
|
12
|
-
security: "Security",
|
|
13
|
-
maintainability: "Maintainability",
|
|
14
|
-
ecosystem: "Ecosystem",
|
|
15
|
-
upgradeImpact: "Upgrade Impact",
|
|
16
|
-
};
|
|
17
|
-
function clampScore(score) {
|
|
18
|
-
if (!Number.isFinite(score))
|
|
19
|
-
return 0;
|
|
20
|
-
return Math.max(0, Math.min(100, Math.round(score)));
|
|
21
|
-
}
|
|
22
|
-
export function deriveOverallRiskBand(score) {
|
|
23
|
-
if (score == null || !Number.isFinite(score))
|
|
24
|
-
return "low";
|
|
25
|
-
const value = clampScore(score);
|
|
26
|
-
if (value >= SCAN_DETAIL_RISK_BAND_HIGH_MIN)
|
|
27
|
-
return "high";
|
|
28
|
-
if (value >= SCAN_DETAIL_RISK_BAND_MODERATE_MIN)
|
|
29
|
-
return "moderate";
|
|
30
|
-
return "low";
|
|
31
|
-
}
|
|
32
|
-
export function overallSignalBandLabel(band) {
|
|
33
|
-
const copy = scanSurfaceCopy.scanDetail.signalSummary.bandLabel;
|
|
34
|
-
if (band === "high")
|
|
35
|
-
return copy.high;
|
|
36
|
-
if (band === "moderate")
|
|
37
|
-
return copy.moderate;
|
|
38
|
-
return copy.low;
|
|
39
|
-
}
|
|
40
|
-
function layerBandToSignal(band) {
|
|
41
|
-
const copy = scanSurfaceCopy.scanDetail.signalSummary.signalLabel;
|
|
42
|
-
if (band === "High") {
|
|
43
|
-
return { level: "high", label: copy.high };
|
|
44
|
-
}
|
|
45
|
-
if (band === "Moderate") {
|
|
46
|
-
return { level: "medium", label: copy.medium };
|
|
47
|
-
}
|
|
48
|
-
return { level: "low", label: copy.low };
|
|
49
|
-
}
|
|
50
|
-
export function deriveRiskScoreGauge(score, band) {
|
|
51
|
-
const clamped = clampScore(score);
|
|
52
|
-
return {
|
|
53
|
-
fillPercent: clamped,
|
|
54
|
-
band,
|
|
55
|
-
ariaLabel: scanSurfaceCopy.scanDetail.signalSummary.gaugeAriaLabel
|
|
56
|
-
.replace("{score}", String(clamped))
|
|
57
|
-
.replace("{band}", overallSignalBandLabel(band)),
|
|
58
|
-
};
|
|
59
|
-
}
|
|
60
|
-
export function deriveSignalSummary(result) {
|
|
61
|
-
if (typeof result.totalScore !== "number" ||
|
|
62
|
-
!Number.isFinite(result.totalScore)) {
|
|
63
|
-
return null;
|
|
64
|
-
}
|
|
65
|
-
const score = clampScore(result.totalScore);
|
|
66
|
-
const overallBand = deriveOverallRiskBand(score);
|
|
67
|
-
const overallLabel = overallSignalBandLabel(overallBand);
|
|
68
|
-
const gauge = deriveRiskScoreGauge(score, overallBand);
|
|
69
|
-
const layers = LAYER_ORDER.map((layer) => {
|
|
70
|
-
const layerScore = typeof result.layerScores?.[layer] === "number"
|
|
71
|
-
? clampScore(result.layerScores[layer])
|
|
72
|
-
: 0;
|
|
73
|
-
const band = layerRiskBandLabel(layerScore);
|
|
74
|
-
const signal = layerBandToSignal(band);
|
|
75
|
-
return {
|
|
76
|
-
layer,
|
|
77
|
-
label: LAYER_LABEL[layer],
|
|
78
|
-
score: layerScore,
|
|
79
|
-
concernLevel: signal.level,
|
|
80
|
-
concernLabel: signal.label,
|
|
81
|
-
};
|
|
82
|
-
});
|
|
83
|
-
return {
|
|
84
|
-
score,
|
|
85
|
-
overallBand,
|
|
86
|
-
overallLabel,
|
|
87
|
-
gauge,
|
|
88
|
-
layers,
|
|
89
|
-
};
|
|
90
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"deriveRiskScoreSummary.test.d.ts","sourceRoot":"","sources":["../src/deriveRiskScoreSummary.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from "vitest";
|
|
2
|
-
import { deriveOverallRiskBand, deriveSignalSummary, SCAN_DETAIL_RISK_BAND_HIGH_MIN, SCAN_DETAIL_RISK_BAND_MODERATE_MIN, } from "./deriveRiskScoreSummary.js";
|
|
3
|
-
const baseResult = {
|
|
4
|
-
totalScore: 71,
|
|
5
|
-
layerScores: {
|
|
6
|
-
security: 80,
|
|
7
|
-
maintainability: 65,
|
|
8
|
-
ecosystem: 55,
|
|
9
|
-
upgradeImpact: 70,
|
|
10
|
-
},
|
|
11
|
-
findings: [],
|
|
12
|
-
generatedAt: "2026-01-01T00:00:00.000Z",
|
|
13
|
-
};
|
|
14
|
-
describe("deriveOverallRiskBand", () => {
|
|
15
|
-
it("uses 40/80 thresholds", () => {
|
|
16
|
-
expect(SCAN_DETAIL_RISK_BAND_MODERATE_MIN).toBe(40);
|
|
17
|
-
expect(SCAN_DETAIL_RISK_BAND_HIGH_MIN).toBe(80);
|
|
18
|
-
expect(deriveOverallRiskBand(39)).toBe("low");
|
|
19
|
-
expect(deriveOverallRiskBand(40)).toBe("moderate");
|
|
20
|
-
expect(deriveOverallRiskBand(71)).toBe("moderate");
|
|
21
|
-
expect(deriveOverallRiskBand(79)).toBe("moderate");
|
|
22
|
-
expect(deriveOverallRiskBand(80)).toBe("high");
|
|
23
|
-
});
|
|
24
|
-
});
|
|
25
|
-
describe("deriveSignalSummary", () => {
|
|
26
|
-
it("returns moderate band for score 71 on safe posture", () => {
|
|
27
|
-
const summary = deriveSignalSummary({
|
|
28
|
-
...baseResult,
|
|
29
|
-
decision: { recommendation: "safe", confidence: "high", reasoning: [] },
|
|
30
|
-
});
|
|
31
|
-
expect(summary?.score).toBe(71);
|
|
32
|
-
expect(summary?.overallBand).toBe("moderate");
|
|
33
|
-
expect(summary?.overallLabel).toBe("Moderate");
|
|
34
|
-
expect(summary?.gauge.fillPercent).toBe(71);
|
|
35
|
-
});
|
|
36
|
-
it("returns null when totalScore is missing", () => {
|
|
37
|
-
expect(deriveSignalSummary({
|
|
38
|
-
...baseResult,
|
|
39
|
-
totalScore: Number.NaN,
|
|
40
|
-
})).toBeNull();
|
|
41
|
-
});
|
|
42
|
-
it("uses short signal labels on layer rows", () => {
|
|
43
|
-
const summary = deriveSignalSummary(baseResult);
|
|
44
|
-
expect(summary?.layers).toHaveLength(4);
|
|
45
|
-
expect(summary?.layers[0]?.concernLabel).toBe("Elevated");
|
|
46
|
-
});
|
|
47
|
-
});
|
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
import { type ObservationSignalFamily } from "./cardObservationCatalog.js";
|
|
2
|
-
import { type MergePosture } from "./riskVocabulary.js";
|
|
3
|
-
import type { ScanResult } from "./types.js";
|
|
4
|
-
export declare const RECOMMENDATION_MAX_ITEMS = 3;
|
|
5
|
-
export declare const RECOMMENDATION_MAX_TITLE_CHARS = 80;
|
|
6
|
-
export declare const RECOMMENDATION_PREFER_MAX_ON_SAFE = 2;
|
|
7
|
-
export declare const RECOMMENDATION_MAX_SIGNALS = 4;
|
|
8
|
-
export declare const RECOMMENDATION_MAX_PACKAGES = 5;
|
|
9
|
-
export type RecommendationPriority = "high" | "medium" | "low";
|
|
10
|
-
/** @deprecated Use RecommendationPriority */
|
|
11
|
-
export type GuidanceUrgency = RecommendationPriority;
|
|
12
|
-
export type GuidanceSource = "insight" | "recommendation" | "signal" | "finding" | "posture_playbook";
|
|
13
|
-
export type ScanDetailRecommendationDetail = {
|
|
14
|
-
why: string;
|
|
15
|
-
whyNow: string;
|
|
16
|
-
signals: string[];
|
|
17
|
-
affectedPackages?: {
|
|
18
|
-
names: string[];
|
|
19
|
-
overflowCount: number;
|
|
20
|
-
};
|
|
21
|
-
expectedBenefit: string;
|
|
22
|
-
};
|
|
23
|
-
export type ScanDetailRecommendation = {
|
|
24
|
-
id: string;
|
|
25
|
-
rank: number;
|
|
26
|
-
title: string;
|
|
27
|
-
priority: RecommendationPriority;
|
|
28
|
-
source: GuidanceSource;
|
|
29
|
-
signalFamily?: ObservationSignalFamily | null;
|
|
30
|
-
detail: ScanDetailRecommendationDetail;
|
|
31
|
-
proofRefs?: {
|
|
32
|
-
findingIds?: string[];
|
|
33
|
-
};
|
|
34
|
-
};
|
|
35
|
-
export type ScanDetailRecommendationCenter = {
|
|
36
|
-
heading: string;
|
|
37
|
-
defaultSelectedId: string;
|
|
38
|
-
items: ScanDetailRecommendation[];
|
|
39
|
-
posture: MergePosture | null;
|
|
40
|
-
scanContext?: string;
|
|
41
|
-
};
|
|
42
|
-
/** @deprecated Use ScanDetailRecommendationCenter */
|
|
43
|
-
export type ScanDetailWhatToDo = {
|
|
44
|
-
items: Array<{
|
|
45
|
-
id: string;
|
|
46
|
-
label: string;
|
|
47
|
-
emphasis: "primary" | "secondary";
|
|
48
|
-
priority: RecommendationPriority;
|
|
49
|
-
source: GuidanceSource;
|
|
50
|
-
}>;
|
|
51
|
-
posture: MergePosture | null;
|
|
52
|
-
};
|
|
53
|
-
export declare const GUIDANCE_ACTION_FOR_FAMILY: Record<ObservationSignalFamily, string>;
|
|
54
|
-
/** Derive the scan detail recommendation center — always returns 1–3 enriched items. */
|
|
55
|
-
export declare function deriveScanDetailRecommendations(result: ScanResult): ScanDetailRecommendationCenter;
|
|
56
|
-
export declare function recommendationTitlesForDedupe(center: ScanDetailRecommendationCenter): Set<string>;
|
|
57
|
-
export declare function findingIdsCoveredByRecommendations(center: ScanDetailRecommendationCenter): Set<string>;
|
|
58
|
-
export declare function verifyLabelsForDedupe(center: ScanDetailRecommendationCenter): Set<string>;
|
|
59
|
-
/** @deprecated Use deriveScanDetailRecommendations */
|
|
60
|
-
export declare function deriveScanDetailGuidance(result: ScanResult): ScanDetailWhatToDo;
|
|
61
|
-
/** @deprecated Use recommendationTitlesForDedupe */
|
|
62
|
-
export declare function guidanceLabelsForDedupe(whatToDo: ScanDetailWhatToDo): Set<string>;
|
|
63
|
-
//# sourceMappingURL=deriveScanDetailRecommendations.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"deriveScanDetailRecommendations.d.ts","sourceRoot":"","sources":["../src/deriveScanDetailRecommendations.ts"],"names":[],"mappings":"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"}
|