@mergesignal/shared 0.6.0 → 0.8.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/affectedAreaLinkage.d.ts +14 -0
- package/dist/affectedAreaLinkage.d.ts.map +1 -0
- package/dist/affectedAreaLinkage.js +100 -0
- package/dist/assessmentLabels.d.ts +1 -1
- package/dist/assessmentLabels.d.ts.map +1 -1
- package/dist/assessmentPresentationUtils.d.ts +6 -0
- package/dist/assessmentPresentationUtils.d.ts.map +1 -0
- package/dist/assessmentPresentationUtils.js +17 -0
- package/dist/assessmentProjection.d.ts +2 -2
- package/dist/assessmentProjection.d.ts.map +1 -1
- package/dist/assessmentProjection.js +42 -13
- package/dist/deriveScanNarrative.d.ts.map +1 -1
- package/dist/deriveScanNarrative.js +92 -9
- package/dist/deriveScanNarrative.test.js +74 -0
- package/dist/engineWireRegression.test.js +1 -1
- package/dist/fixtures/assessmentFixtures.d.ts +2 -1
- package/dist/fixtures/assessmentFixtures.d.ts.map +1 -1
- package/dist/fixtures/assessmentFixtures.js +78 -23
- package/dist/fixtures/assessmentScopeFixtures.d.ts +17 -0
- package/dist/fixtures/assessmentScopeFixtures.d.ts.map +1 -0
- package/dist/fixtures/assessmentScopeFixtures.js +42 -0
- package/dist/formatCardExposureDisplay.d.ts +5 -3
- package/dist/formatCardExposureDisplay.d.ts.map +1 -1
- package/dist/formatCardExposureDisplay.js +12 -5
- package/dist/formatCardExposureDisplay.test.js +9 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/presentation/buildGitHubCheckRunOutput.test.js +16 -41
- package/dist/presentation/compose/narrativeChannels.js +1 -1
- package/dist/presentation/dto/assessmentPresentationFields.d.ts +1 -2
- package/dist/presentation/dto/assessmentPresentationFields.d.ts.map +1 -1
- package/dist/presentation/fixtures/scanResultFixtures.d.ts.map +1 -1
- package/dist/presentation/fixtures/scanResultFixtures.js +19 -1
- package/dist/presentation/orchestration/buildScanPresentationBundle.d.ts.map +1 -1
- package/dist/presentation/orchestration/buildScanPresentationBundle.js +12 -5
- package/dist/presentation/orchestration/buildScanPresentationBundle.test.d.ts +2 -0
- package/dist/presentation/orchestration/buildScanPresentationBundle.test.d.ts.map +1 -0
- package/dist/presentation/orchestration/buildScanPresentationBundle.test.js +99 -0
- package/dist/presentation/orchestration/scanPresentationBundle.d.ts +1 -1
- package/dist/presentation/orchestration/scanPresentationBundle.d.ts.map +1 -1
- package/dist/presentation/presentation.test.js +1 -1
- package/dist/presentation/presentationPersonas.test.js +0 -5
- package/dist/presentation/profile/buildProfileFromAssessment.d.ts +1 -1
- package/dist/presentation/profile/buildProfileFromAssessment.d.ts.map +1 -1
- package/dist/presentation/profile/buildProfileFromAssessment.js +13 -2
- package/dist/presentation/surfaceParity.test.js +73 -5
- package/dist/repoIntelligenceSchema.d.ts +3 -3
- package/dist/riskSignals.d.ts +19 -0
- package/dist/riskSignals.d.ts.map +1 -0
- package/dist/riskSignals.js +32 -0
- package/dist/scanNarrativeFacts.d.ts +25 -7
- package/dist/scanNarrativeFacts.d.ts.map +1 -1
- package/dist/scanNarrativeFacts.js +4 -1
- package/dist/scanPresentationBundle.golden.test.d.ts +2 -0
- package/dist/scanPresentationBundle.golden.test.d.ts.map +1 -0
- package/dist/scanPresentationBundle.golden.test.js +78 -0
- package/dist/scanResultSchema.d.ts +53 -4
- package/dist/scanResultSchema.d.ts.map +1 -1
- package/dist/scanResultSchema.js +1 -1
- package/dist/scanResultSchema.test.js +26 -0
- package/dist/types.d.ts +1 -1
- package/dist/types.d.ts.map +1 -1
- package/package.json +4 -2
- package/dist/assessmentSchema.d.ts +0 -155
- package/dist/assessmentSchema.d.ts.map +0 -1
- package/dist/assessmentSchema.js +0 -110
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { emptyReachScope, emptyVerificationScope, minimalReviewFocalPoint, reachScopeFor, verificationScopeFor, withAssessmentScope, } from "./assessmentScopeFixtures.js";
|
|
1
2
|
const safeToolingPresentation = {
|
|
2
3
|
narrativeIntensity: "minimal",
|
|
3
4
|
reachVisibility: "hidden",
|
|
@@ -12,7 +13,7 @@ const runtimeReviewPresentation = {
|
|
|
12
13
|
insightEmissionFloor: "full",
|
|
13
14
|
reportMode: "high_signal_pr",
|
|
14
15
|
};
|
|
15
|
-
export const assessmentTypescriptPatch = {
|
|
16
|
+
export const assessmentTypescriptPatch = withAssessmentScope({
|
|
16
17
|
posture: "safe",
|
|
17
18
|
confidence: "high",
|
|
18
19
|
primaryConcern: null,
|
|
@@ -20,15 +21,27 @@ export const assessmentTypescriptPatch = {
|
|
|
20
21
|
factors: ["tooling_maintenance"],
|
|
21
22
|
changeClasses: ["tooling_maintenance"],
|
|
22
23
|
presentation: safeToolingPresentation,
|
|
23
|
-
}
|
|
24
|
-
|
|
24
|
+
}, {
|
|
25
|
+
reviewFocalPoint: minimalReviewFocalPoint(["typescript"]),
|
|
26
|
+
reachScope: emptyReachScope(),
|
|
27
|
+
verificationScope: emptyVerificationScope(),
|
|
28
|
+
});
|
|
29
|
+
export const assessmentPrettier = withAssessmentScope({
|
|
25
30
|
...assessmentTypescriptPatch,
|
|
26
31
|
factors: ["tooling_maintenance"],
|
|
27
|
-
}
|
|
28
|
-
|
|
32
|
+
}, {
|
|
33
|
+
reviewFocalPoint: minimalReviewFocalPoint(["prettier"]),
|
|
34
|
+
reachScope: emptyReachScope(),
|
|
35
|
+
verificationScope: emptyVerificationScope(),
|
|
36
|
+
});
|
|
37
|
+
export const assessmentEslint = withAssessmentScope({
|
|
29
38
|
...assessmentTypescriptPatch,
|
|
30
|
-
}
|
|
31
|
-
|
|
39
|
+
}, {
|
|
40
|
+
reviewFocalPoint: minimalReviewFocalPoint(["eslint"]),
|
|
41
|
+
reachScope: emptyReachScope(),
|
|
42
|
+
verificationScope: emptyVerificationScope(),
|
|
43
|
+
});
|
|
44
|
+
export const assessmentVitest = withAssessmentScope({
|
|
32
45
|
posture: "safe",
|
|
33
46
|
confidence: "high",
|
|
34
47
|
primaryConcern: null,
|
|
@@ -36,8 +49,12 @@ export const assessmentVitest = {
|
|
|
36
49
|
factors: ["test_infra_change"],
|
|
37
50
|
changeClasses: ["test_infra"],
|
|
38
51
|
presentation: safeToolingPresentation,
|
|
39
|
-
}
|
|
40
|
-
|
|
52
|
+
}, {
|
|
53
|
+
reviewFocalPoint: minimalReviewFocalPoint(["vitest"]),
|
|
54
|
+
reachScope: emptyReachScope(),
|
|
55
|
+
verificationScope: emptyVerificationScope(),
|
|
56
|
+
});
|
|
57
|
+
export const assessmentFastifyRuntime = withAssessmentScope({
|
|
41
58
|
posture: "needs_review",
|
|
42
59
|
confidence: "medium",
|
|
43
60
|
primaryConcern: "confirmed_runtime_usage",
|
|
@@ -52,8 +69,12 @@ export const assessmentFastifyRuntime = {
|
|
|
52
69
|
factors: ["confirmed_runtime_usage", "http_framework_infrastructure"],
|
|
53
70
|
changeClasses: ["runtime_upgrade"],
|
|
54
71
|
presentation: runtimeReviewPresentation,
|
|
55
|
-
}
|
|
56
|
-
|
|
72
|
+
}, {
|
|
73
|
+
reviewFocalPoint: minimalReviewFocalPoint(["fastify"]),
|
|
74
|
+
reachScope: reachScopeFor(["fastify"]),
|
|
75
|
+
verificationScope: verificationScopeFor(["fastify"], ["routes", "middleware"]),
|
|
76
|
+
});
|
|
77
|
+
export const assessmentBullmq = withAssessmentScope({
|
|
57
78
|
posture: "needs_review",
|
|
58
79
|
confidence: "medium",
|
|
59
80
|
primaryConcern: "confirmed_runtime_usage",
|
|
@@ -72,8 +93,12 @@ export const assessmentBullmq = {
|
|
|
72
93
|
],
|
|
73
94
|
changeClasses: ["runtime_upgrade"],
|
|
74
95
|
presentation: runtimeReviewPresentation,
|
|
75
|
-
}
|
|
76
|
-
|
|
96
|
+
}, {
|
|
97
|
+
reviewFocalPoint: minimalReviewFocalPoint(["bullmq"]),
|
|
98
|
+
reachScope: reachScopeFor(["bullmq"]),
|
|
99
|
+
verificationScope: verificationScopeFor(["bullmq"], ["workers", "queue", "serialization"]),
|
|
100
|
+
});
|
|
101
|
+
export const assessmentNextAuth = withAssessmentScope({
|
|
77
102
|
posture: "needs_review",
|
|
78
103
|
confidence: "medium",
|
|
79
104
|
primaryConcern: "confirmed_runtime_usage",
|
|
@@ -88,8 +113,13 @@ export const assessmentNextAuth = {
|
|
|
88
113
|
factors: ["confirmed_runtime_usage", "auth_infrastructure"],
|
|
89
114
|
changeClasses: ["runtime_upgrade"],
|
|
90
115
|
presentation: runtimeReviewPresentation,
|
|
91
|
-
}
|
|
92
|
-
|
|
116
|
+
}, {
|
|
117
|
+
reviewFocalPoint: minimalReviewFocalPoint(["next-auth"]),
|
|
118
|
+
reachScope: reachScopeFor(["next-auth"]),
|
|
119
|
+
verificationScope: verificationScopeFor(["next-auth"], ["auth_flow", "session", "routes"]),
|
|
120
|
+
});
|
|
121
|
+
/** PR #26 — focal fastify despite typescript in changedPackages order. */
|
|
122
|
+
export const assessmentMixedTypescriptFastify = withAssessmentScope({
|
|
93
123
|
posture: "needs_review",
|
|
94
124
|
confidence: "medium",
|
|
95
125
|
primaryConcern: "confirmed_runtime_usage",
|
|
@@ -101,11 +131,22 @@ export const assessmentMixedTypescriptFastify = {
|
|
|
101
131
|
evidenceRefs: ["fixture:fastify"],
|
|
102
132
|
},
|
|
103
133
|
],
|
|
104
|
-
factors: [
|
|
134
|
+
factors: [
|
|
135
|
+
"confirmed_runtime_usage",
|
|
136
|
+
"queue_infrastructure",
|
|
137
|
+
"http_framework_infrastructure",
|
|
138
|
+
],
|
|
105
139
|
changeClasses: ["runtime_upgrade", "tooling_maintenance"],
|
|
106
140
|
presentation: runtimeReviewPresentation,
|
|
107
|
-
}
|
|
108
|
-
|
|
141
|
+
}, {
|
|
142
|
+
reviewFocalPoint: minimalReviewFocalPoint(["fastify"], {
|
|
143
|
+
episodeShape: "parent_supporting",
|
|
144
|
+
supportingPackages: ["bullmq", "next-auth"],
|
|
145
|
+
}),
|
|
146
|
+
reachScope: reachScopeFor(["bullmq", "fastify", "next-auth"]),
|
|
147
|
+
verificationScope: verificationScopeFor(["bullmq", "fastify", "next-auth"], ["workers", "queue", "routes", "middleware"]),
|
|
148
|
+
});
|
|
149
|
+
export const assessmentLimitedContext = withAssessmentScope({
|
|
109
150
|
posture: "needs_review",
|
|
110
151
|
confidence: "low",
|
|
111
152
|
primaryConcern: "insufficient_evidence",
|
|
@@ -125,8 +166,12 @@ export const assessmentLimitedContext = {
|
|
|
125
166
|
insightEmissionFloor: "none",
|
|
126
167
|
reportMode: "high_signal_pr",
|
|
127
168
|
},
|
|
128
|
-
}
|
|
129
|
-
|
|
169
|
+
}, {
|
|
170
|
+
reviewFocalPoint: minimalReviewFocalPoint(["lodash"]),
|
|
171
|
+
reachScope: emptyReachScope(),
|
|
172
|
+
verificationScope: emptyVerificationScope(),
|
|
173
|
+
});
|
|
174
|
+
export const assessmentStub = withAssessmentScope({
|
|
130
175
|
posture: "needs_review",
|
|
131
176
|
confidence: "low",
|
|
132
177
|
primaryConcern: "insufficient_evidence",
|
|
@@ -146,8 +191,14 @@ export const assessmentStub = {
|
|
|
146
191
|
insightEmissionFloor: "none",
|
|
147
192
|
reportMode: "high_signal_pr",
|
|
148
193
|
},
|
|
149
|
-
}
|
|
150
|
-
|
|
194
|
+
}, {
|
|
195
|
+
reviewFocalPoint: minimalReviewFocalPoint(["dependency_graph"], {
|
|
196
|
+
episodeShape: "structural",
|
|
197
|
+
}),
|
|
198
|
+
reachScope: emptyReachScope(),
|
|
199
|
+
verificationScope: emptyVerificationScope(),
|
|
200
|
+
});
|
|
201
|
+
export const assessmentUnknownSafe = withAssessmentScope({
|
|
151
202
|
posture: "safe",
|
|
152
203
|
confidence: "medium",
|
|
153
204
|
primaryConcern: null,
|
|
@@ -161,4 +212,8 @@ export const assessmentUnknownSafe = {
|
|
|
161
212
|
insightEmissionFloor: "explain_only",
|
|
162
213
|
reportMode: "high_signal_pr",
|
|
163
214
|
},
|
|
164
|
-
}
|
|
215
|
+
}, {
|
|
216
|
+
reviewFocalPoint: minimalReviewFocalPoint(["opaque-pkg"]),
|
|
217
|
+
reachScope: emptyReachScope(),
|
|
218
|
+
verificationScope: emptyVerificationScope(),
|
|
219
|
+
});
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { Assessment, FocalElectionDimension, ReachScope, ReviewEpisodeShape, ReviewFocalPoint, VerificationScope } from "@mergesignal/contracts";
|
|
2
|
+
export declare function minimalReviewFocalPoint(anchors: string[], opts?: {
|
|
3
|
+
episodeShape?: ReviewEpisodeShape;
|
|
4
|
+
supportingPackages?: string[];
|
|
5
|
+
decidedBy?: FocalElectionDimension;
|
|
6
|
+
}): ReviewFocalPoint;
|
|
7
|
+
export declare function emptyReachScope(): ReachScope;
|
|
8
|
+
export declare function reachScopeFor(packages: string[], maxBucket?: ReachScope["maxBucket"]): ReachScope;
|
|
9
|
+
export declare function emptyVerificationScope(): VerificationScope;
|
|
10
|
+
export declare function verificationScopeFor(packages: string[], focus?: string[]): VerificationScope;
|
|
11
|
+
/** Attach focal/scope fields required by assessmentSchema ABI 2. */
|
|
12
|
+
export declare function withAssessmentScope(assessment: Omit<Assessment, "reviewFocalPoint" | "reachScope" | "verificationScope">, scope: {
|
|
13
|
+
reviewFocalPoint: ReviewFocalPoint;
|
|
14
|
+
reachScope?: ReachScope;
|
|
15
|
+
verificationScope?: VerificationScope;
|
|
16
|
+
}): Assessment;
|
|
17
|
+
//# sourceMappingURL=assessmentScopeFixtures.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"assessmentScopeFixtures.d.ts","sourceRoot":"","sources":["../../src/fixtures/assessmentScopeFixtures.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,UAAU,EACV,sBAAsB,EACtB,UAAU,EACV,kBAAkB,EAClB,gBAAgB,EAChB,iBAAiB,EAClB,MAAM,wBAAwB,CAAC;AAEhC,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,MAAM,EAAE,EACjB,IAAI,CAAC,EAAE;IACL,YAAY,CAAC,EAAE,kBAAkB,CAAC;IAClC,kBAAkB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC9B,SAAS,CAAC,EAAE,sBAAsB,CAAC;CACpC,GACA,gBAAgB,CAoBlB;AAED,wBAAgB,eAAe,IAAI,UAAU,CAE5C;AAED,wBAAgB,aAAa,CAC3B,QAAQ,EAAE,MAAM,EAAE,EAClB,SAAS,GAAE,UAAU,CAAC,WAAW,CAAc,GAC9C,UAAU,CAEZ;AAED,wBAAgB,sBAAsB,IAAI,iBAAiB,CAE1D;AAED,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,MAAM,EAAE,EAClB,KAAK,GAAE,MAAM,EAAO,GACnB,iBAAiB,CAEnB;AAED,oEAAoE;AACpE,wBAAgB,mBAAmB,CACjC,UAAU,EAAE,IAAI,CACd,UAAU,EACV,kBAAkB,GAAG,YAAY,GAAG,mBAAmB,CACxD,EACD,KAAK,EAAE;IACL,gBAAgB,EAAE,gBAAgB,CAAC;IACnC,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB,iBAAiB,CAAC,EAAE,iBAAiB,CAAC;CACvC,GACA,UAAU,CAOZ"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
export function minimalReviewFocalPoint(anchors, opts) {
|
|
2
|
+
const episodeShape = opts?.episodeShape ?? "single_anchor";
|
|
3
|
+
const decidedBy = opts?.decidedBy ?? "reach";
|
|
4
|
+
const primary = anchors[0] ?? "dependency";
|
|
5
|
+
return {
|
|
6
|
+
episodeShape,
|
|
7
|
+
anchors,
|
|
8
|
+
supportingPackages: opts?.supportingPackages,
|
|
9
|
+
election: {
|
|
10
|
+
grounding: [
|
|
11
|
+
{
|
|
12
|
+
packageName: primary,
|
|
13
|
+
reason: "fixture",
|
|
14
|
+
decidedBy,
|
|
15
|
+
evidenceRefs: ["fixture:focal"],
|
|
16
|
+
},
|
|
17
|
+
],
|
|
18
|
+
exclusions: [],
|
|
19
|
+
},
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
export function emptyReachScope() {
|
|
23
|
+
return { packages: [], maxBucket: "very_low" };
|
|
24
|
+
}
|
|
25
|
+
export function reachScopeFor(packages, maxBucket = "moderate") {
|
|
26
|
+
return { packages, maxBucket };
|
|
27
|
+
}
|
|
28
|
+
export function emptyVerificationScope() {
|
|
29
|
+
return { packages: [], focus: [] };
|
|
30
|
+
}
|
|
31
|
+
export function verificationScopeFor(packages, focus = []) {
|
|
32
|
+
return { packages, focus };
|
|
33
|
+
}
|
|
34
|
+
/** Attach focal/scope fields required by assessmentSchema ABI 2. */
|
|
35
|
+
export function withAssessmentScope(assessment, scope) {
|
|
36
|
+
return {
|
|
37
|
+
...assessment,
|
|
38
|
+
reviewFocalPoint: scope.reviewFocalPoint,
|
|
39
|
+
reachScope: scope.reachScope ?? emptyReachScope(),
|
|
40
|
+
verificationScope: scope.verificationScope ?? emptyVerificationScope(),
|
|
41
|
+
};
|
|
42
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
2
|
+
* Canonical exposure bucket thresholds for numeric risk scores (0–100).
|
|
3
|
+
* Consumed by `deriveRiskSignals` for bundle facts; label formatters remain for aria copy.
|
|
4
4
|
*/
|
|
5
5
|
export type CardExposureCategory = "minimal" | "limited" | "moderate" | "elevated" | "broad";
|
|
6
6
|
export type CardExposureDisplay = {
|
|
@@ -11,7 +11,9 @@ export type CardExposureDisplay = {
|
|
|
11
11
|
};
|
|
12
12
|
/** User-facing exposure labels for docs and UI copy (low → high). */
|
|
13
13
|
export declare const CARD_EXPOSURE_CATEGORY_LABELS: readonly string[];
|
|
14
|
-
/** Map numeric
|
|
14
|
+
/** Map numeric score to a fixed exposure category (canonical thresholds). */
|
|
15
|
+
export declare function deriveCardExposureCategory(score: number | null | undefined): CardExposureCategory | null;
|
|
16
|
+
/** Map numeric totalScore to exposure category + display label. */
|
|
15
17
|
export declare function deriveCardExposureDisplay(score: number | null | undefined): CardExposureDisplay | null;
|
|
16
18
|
/** Compact card line: exposure category label only. */
|
|
17
19
|
export declare function formatCardExposureLine(score: number | null | undefined): string | null;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"formatCardExposureDisplay.d.ts","sourceRoot":"","sources":["../src/formatCardExposureDisplay.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,MAAM,oBAAoB,GAC5B,SAAS,GACT,SAAS,GACT,UAAU,GACV,UAAU,GACV,OAAO,CAAC;AAEZ,MAAM,MAAM,mBAAmB,GAAG;IAChC,QAAQ,EAAE,oBAAoB,CAAC;IAC/B,mDAAmD;IACnD,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAUF,qEAAqE;AACrE,eAAO,MAAM,6BAA6B,EAAE,SAAS,MAAM,EAM1D,CAAC;AAkBF,
|
|
1
|
+
{"version":3,"file":"formatCardExposureDisplay.d.ts","sourceRoot":"","sources":["../src/formatCardExposureDisplay.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,MAAM,oBAAoB,GAC5B,SAAS,GACT,SAAS,GACT,UAAU,GACV,UAAU,GACV,OAAO,CAAC;AAEZ,MAAM,MAAM,mBAAmB,GAAG;IAChC,QAAQ,EAAE,oBAAoB,CAAC;IAC/B,mDAAmD;IACnD,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAUF,qEAAqE;AACrE,eAAO,MAAM,6BAA6B,EAAE,SAAS,MAAM,EAM1D,CAAC;AAkBF,6EAA6E;AAC7E,wBAAgB,0BAA0B,CACxC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAC/B,oBAAoB,GAAG,IAAI,CAK7B;AAED,mEAAmE;AACnE,wBAAgB,yBAAyB,CACvC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAC/B,mBAAmB,GAAG,IAAI,CAK5B;AAED,uDAAuD;AACvD,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAC/B,MAAM,GAAG,IAAI,CAIf;AAED,sDAAsD;AACtD,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAC/B,MAAM,GAAG,IAAI,CAIf"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
2
|
+
* Canonical exposure bucket thresholds for numeric risk scores (0–100).
|
|
3
|
+
* Consumed by `deriveRiskSignals` for bundle facts; label formatters remain for aria copy.
|
|
4
4
|
*/
|
|
5
5
|
const EXPOSURE_LABEL = {
|
|
6
6
|
minimal: "Minimal exposure",
|
|
@@ -31,13 +31,20 @@ function clampScore(score) {
|
|
|
31
31
|
return 0;
|
|
32
32
|
return Math.min(100, Math.max(0, Math.round(score)));
|
|
33
33
|
}
|
|
34
|
-
/** Map numeric
|
|
35
|
-
export function
|
|
34
|
+
/** Map numeric score to a fixed exposure category (canonical thresholds). */
|
|
35
|
+
export function deriveCardExposureCategory(score) {
|
|
36
36
|
if (score == null || !Number.isFinite(score))
|
|
37
37
|
return null;
|
|
38
38
|
const value = clampScore(score);
|
|
39
39
|
const idx = EXPOSURE_UPPER_BOUND.findIndex((bound) => value <= bound);
|
|
40
|
-
|
|
40
|
+
return EXPOSURE_ORDER[idx >= 0 ? idx : EXPOSURE_ORDER.length - 1];
|
|
41
|
+
}
|
|
42
|
+
/** Map numeric totalScore to exposure category + display label. */
|
|
43
|
+
export function deriveCardExposureDisplay(score) {
|
|
44
|
+
const category = deriveCardExposureCategory(score);
|
|
45
|
+
if (category == null)
|
|
46
|
+
return null;
|
|
47
|
+
const value = clampScore(score);
|
|
41
48
|
return { category, label: EXPOSURE_LABEL[category], value };
|
|
42
49
|
}
|
|
43
50
|
/** Compact card line: exposure category label only. */
|
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
import { describe, expect, it } from "vitest";
|
|
2
|
-
import { deriveCardExposureDisplay, exposureAriaFragment, formatCardExposureLine, } from "./formatCardExposureDisplay.js";
|
|
2
|
+
import { deriveCardExposureCategory, deriveCardExposureDisplay, exposureAriaFragment, formatCardExposureLine, } from "./formatCardExposureDisplay.js";
|
|
3
|
+
describe("deriveCardExposureCategory", () => {
|
|
4
|
+
it("maps score ranges to exposure categories", () => {
|
|
5
|
+
expect(deriveCardExposureCategory(0)).toBe("minimal");
|
|
6
|
+
expect(deriveCardExposureCategory(45)).toBe("moderate");
|
|
7
|
+
expect(deriveCardExposureCategory(90)).toBe("broad");
|
|
8
|
+
expect(deriveCardExposureCategory(null)).toBeNull();
|
|
9
|
+
});
|
|
10
|
+
});
|
|
3
11
|
describe("deriveCardExposureDisplay", () => {
|
|
4
12
|
it("maps score to five fixed exposure buckets", () => {
|
|
5
13
|
expect(deriveCardExposureDisplay(0)?.category).toBe("minimal");
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
export * from "./types.js";
|
|
2
|
-
export * from "./assessmentSchema.js";
|
|
3
2
|
export * from "./assessmentLabels.js";
|
|
4
3
|
export * from "./assessmentProjection.js";
|
|
5
4
|
export * from "./formatInsight.js";
|
|
@@ -29,4 +28,6 @@ export * from "./trustedScanGuards.js";
|
|
|
29
28
|
export * from "./actionsStepSummary.js";
|
|
30
29
|
export * from "./productMessaging.js";
|
|
31
30
|
export * from "./presentation/index.js";
|
|
31
|
+
export { emptyReachScope, emptyVerificationScope, minimalReviewFocalPoint, reachScopeFor, verificationScopeFor, withAssessmentScope, } from "./fixtures/assessmentScopeFixtures.js";
|
|
32
|
+
export { assessmentStub, assessmentTypescriptPatch, } from "./fixtures/assessmentFixtures.js";
|
|
32
33
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,uBAAuB,CAAC;AACtC,cAAc,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,uBAAuB,CAAC;AACtC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,oBAAoB,CAAC;AACnC,cAAc,qBAAqB,CAAC;AACpC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,sBAAsB,CAAC;AACrC,cAAc,0BAA0B,CAAC;AACzC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,yBAAyB,CAAC;AACxC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,8BAA8B,CAAC;AAC7C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,iCAAiC,CAAC;AAChD,cAAc,0BAA0B,CAAC;AACzC,cAAc,oCAAoC,CAAC;AACnD,cAAc,4BAA4B,CAAC;AAC3C,cAAc,6BAA6B,CAAC;AAC5C,OAAO,EAAE,wCAAwC,EAAE,MAAM,6BAA6B,CAAC;AACvF,cAAc,+BAA+B,CAAC;AAC9C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,uBAAuB,CAAC;AACtC,cAAc,sBAAsB,CAAC;AACrC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,wBAAwB,CAAC;AACvC,cAAc,yBAAyB,CAAC;AACxC,cAAc,uBAAuB,CAAC;AACtC,cAAc,yBAAyB,CAAC;AACxC,OAAO,EACL,eAAe,EACf,sBAAsB,EACtB,uBAAuB,EACvB,aAAa,EACb,oBAAoB,EACpB,mBAAmB,GACpB,MAAM,uCAAuC,CAAC;AAC/C,OAAO,EACL,cAAc,EACd,yBAAyB,GAC1B,MAAM,kCAAkC,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
export * from "./types.js";
|
|
2
|
-
export * from "./assessmentSchema.js";
|
|
3
2
|
export * from "./assessmentLabels.js";
|
|
4
3
|
export * from "./assessmentProjection.js";
|
|
5
4
|
export * from "./formatInsight.js";
|
|
@@ -29,3 +28,5 @@ export * from "./trustedScanGuards.js";
|
|
|
29
28
|
export * from "./actionsStepSummary.js";
|
|
30
29
|
export * from "./productMessaging.js";
|
|
31
30
|
export * from "./presentation/index.js";
|
|
31
|
+
export { emptyReachScope, emptyVerificationScope, minimalReviewFocalPoint, reachScopeFor, verificationScopeFor, withAssessmentScope, } from "./fixtures/assessmentScopeFixtures.js";
|
|
32
|
+
export { assessmentStub, assessmentTypescriptPatch, } from "./fixtures/assessmentFixtures.js";
|
|
@@ -1,22 +1,10 @@
|
|
|
1
1
|
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { assessmentFastifyRuntime, assessmentTypescriptPatch, } from "../fixtures/assessmentFixtures.js";
|
|
3
|
+
import { withAssessmentScope, minimalReviewFocalPoint, emptyReachScope, emptyVerificationScope, reachScopeFor, } from "../fixtures/assessmentScopeFixtures.js";
|
|
2
4
|
import { buildScanPresentationBundle, presentDashboardCard } from "./index.js";
|
|
3
5
|
import { buildGitHubCheckRunOutput } from "./buildGitHubCheckRunOutput.js";
|
|
4
|
-
const safeAssessment =
|
|
5
|
-
|
|
6
|
-
confidence: "high",
|
|
7
|
-
primaryConcern: null,
|
|
8
|
-
concerns: [],
|
|
9
|
-
factors: ["tooling_maintenance"],
|
|
10
|
-
changeClasses: ["tooling_maintenance"],
|
|
11
|
-
presentation: {
|
|
12
|
-
narrativeIntensity: "minimal",
|
|
13
|
-
reachVisibility: "hidden",
|
|
14
|
-
verificationIntensity: "advisory",
|
|
15
|
-
insightEmissionFloor: "none",
|
|
16
|
-
reportMode: "high_signal_pr",
|
|
17
|
-
},
|
|
18
|
-
};
|
|
19
|
-
const baselineAssessment = {
|
|
6
|
+
const safeAssessment = assessmentTypescriptPatch;
|
|
7
|
+
const baselineAssessment = withAssessmentScope({
|
|
20
8
|
posture: "safe",
|
|
21
9
|
confidence: "medium",
|
|
22
10
|
primaryConcern: "graph_baseline_only",
|
|
@@ -36,30 +24,13 @@ const baselineAssessment = {
|
|
|
36
24
|
insightEmissionFloor: "none",
|
|
37
25
|
reportMode: "lightweight_pr_graph_baseline",
|
|
38
26
|
},
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
kind: "confirmed_runtime_usage",
|
|
47
|
-
rank: 1,
|
|
48
|
-
packages: ["fastify"],
|
|
49
|
-
evidenceRefs: ["fixture:fastify"],
|
|
50
|
-
},
|
|
51
|
-
],
|
|
52
|
-
factors: ["confirmed_runtime_usage", "http_framework_infrastructure"],
|
|
53
|
-
changeClasses: ["runtime_upgrade"],
|
|
54
|
-
presentation: {
|
|
55
|
-
narrativeIntensity: "elevated",
|
|
56
|
-
reachVisibility: "prominent",
|
|
57
|
-
verificationIntensity: "required",
|
|
58
|
-
insightEmissionFloor: "full",
|
|
59
|
-
reportMode: "high_signal_pr",
|
|
60
|
-
},
|
|
61
|
-
};
|
|
62
|
-
const riskyAssessment = {
|
|
27
|
+
}, {
|
|
28
|
+
reviewFocalPoint: minimalReviewFocalPoint(["@types/minimist"]),
|
|
29
|
+
reachScope: emptyReachScope(),
|
|
30
|
+
verificationScope: emptyVerificationScope(),
|
|
31
|
+
});
|
|
32
|
+
const needsReviewAssessment = assessmentFastifyRuntime;
|
|
33
|
+
const riskyAssessment = withAssessmentScope({
|
|
63
34
|
posture: "risky",
|
|
64
35
|
confidence: "high",
|
|
65
36
|
primaryConcern: "breaking_or_major",
|
|
@@ -80,7 +51,11 @@ const riskyAssessment = {
|
|
|
80
51
|
insightEmissionFloor: "full",
|
|
81
52
|
reportMode: "high_signal_pr",
|
|
82
53
|
},
|
|
83
|
-
}
|
|
54
|
+
}, {
|
|
55
|
+
reviewFocalPoint: minimalReviewFocalPoint(["react"]),
|
|
56
|
+
reachScope: reachScopeFor(["react"], "high"),
|
|
57
|
+
verificationScope: emptyVerificationScope(),
|
|
58
|
+
});
|
|
84
59
|
function assertNoLegacyCheckRunMarkers(summary) {
|
|
85
60
|
expect(summary).not.toContain("Risk index");
|
|
86
61
|
expect(summary).not.toContain("Layer scores");
|
|
@@ -19,7 +19,7 @@ export function buildNarrativeChannels(bundle) {
|
|
|
19
19
|
const { assessment, presentation, profile, result } = bundle;
|
|
20
20
|
const reachLabel = reachVisibilityLabel(presentation.reachVisibility);
|
|
21
21
|
return {
|
|
22
|
-
headline: formatAssessmentHeadline(assessment,
|
|
22
|
+
headline: formatAssessmentHeadline(assessment, profile.status),
|
|
23
23
|
limitedContextMessage: profile.degradedMessage ?? undefined,
|
|
24
24
|
reachLabel,
|
|
25
25
|
insights: projectInsightLines(assessment, result),
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import type { MergeConcernKind } from "
|
|
2
|
-
import type { NarrativeIntensity, ReachVisibility } from "../../assessmentSchema.js";
|
|
1
|
+
import type { MergeConcernKind, NarrativeIntensity, ReachVisibility } from "@mergesignal/contracts";
|
|
3
2
|
/** Assessment-aligned fields projected identically across surfaces. */
|
|
4
3
|
export type AssessmentPresentationFields = {
|
|
5
4
|
posture: "safe" | "needs_review" | "risky";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"assessmentPresentationFields.d.ts","sourceRoot":"","sources":["../../../src/presentation/dto/assessmentPresentationFields.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"assessmentPresentationFields.d.ts","sourceRoot":"","sources":["../../../src/presentation/dto/assessmentPresentationFields.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,gBAAgB,EAChB,kBAAkB,EAClB,eAAe,EAEhB,MAAM,wBAAwB,CAAC;AAEhC,uEAAuE;AACvE,MAAM,MAAM,4BAA4B,GAAG;IACzC,OAAO,EAAE,MAAM,GAAG,cAAc,GAAG,OAAO,CAAC;IAC3C,cAAc,EAAE,gBAAgB,GAAG,IAAI,CAAC;IACxC,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,iBAAiB,EAAE,MAAM,EAAE,CAAC;IAC5B,eAAe,EAAE,eAAe,CAAC;IACjC,kBAAkB,EAAE,kBAAkB,CAAC;CACxC,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scanResultFixtures.d.ts","sourceRoot":"","sources":["../../../src/presentation/fixtures/scanResultFixtures.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAYjD,eAAO,MAAM,wBAAwB,EAAE,
|
|
1
|
+
{"version":3,"file":"scanResultFixtures.d.ts","sourceRoot":"","sources":["../../../src/presentation/fixtures/scanResultFixtures.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAYjD,eAAO,MAAM,wBAAwB,EAAE,UA0CtC,CAAC;AAEF,eAAO,MAAM,yBAAyB,EAAE,UA2BvC,CAAC;AAEF,eAAO,MAAM,wBAAwB,EAAE,UAqCtC,CAAC"}
|
|
@@ -9,7 +9,16 @@ export const scanResultFastifyRuntime = {
|
|
|
9
9
|
ecosystem: 30,
|
|
10
10
|
upgradeImpact: 15,
|
|
11
11
|
},
|
|
12
|
-
findings: [
|
|
12
|
+
findings: [
|
|
13
|
+
{
|
|
14
|
+
id: "finding-fastify-runtime",
|
|
15
|
+
title: "Runtime middleware coupling",
|
|
16
|
+
description: "Fastify middleware ordering may affect auth paths.",
|
|
17
|
+
severity: "medium",
|
|
18
|
+
packageName: "fastify",
|
|
19
|
+
recommendation: "Run auth smoke tests",
|
|
20
|
+
},
|
|
21
|
+
],
|
|
13
22
|
generatedAt: "2026-01-01T00:00:00.000Z",
|
|
14
23
|
changedPackages: ["fastify"],
|
|
15
24
|
analysisPreparation: analysisPreparationWithValidRepoIntel(),
|
|
@@ -74,6 +83,15 @@ export const scanResultLimitedContext = {
|
|
|
74
83
|
findings: [],
|
|
75
84
|
generatedAt: "2026-01-01T00:00:00.000Z",
|
|
76
85
|
changedPackages: ["lodash"],
|
|
86
|
+
analysisPreparation: {
|
|
87
|
+
codeIntelligenceAvailable: false,
|
|
88
|
+
warnings: [
|
|
89
|
+
{
|
|
90
|
+
code: "base_lockfile_missing",
|
|
91
|
+
message: "Base lockfile not available for diff",
|
|
92
|
+
},
|
|
93
|
+
],
|
|
94
|
+
},
|
|
77
95
|
repoIntelligence: { invalid: true },
|
|
78
96
|
assessment: assessmentLimitedContext,
|
|
79
97
|
graphInsights: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"buildScanPresentationBundle.d.ts","sourceRoot":"","sources":["../../../src/presentation/orchestration/buildScanPresentationBundle.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"buildScanPresentationBundle.d.ts","sourceRoot":"","sources":["../../../src/presentation/orchestration/buildScanPresentationBundle.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAEtD,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AAE1E,MAAM,MAAM,gCAAgC,GAAG;IAC7C,MAAM,EAAE,UAAU,CAAC;IACnB,cAAc,EAAE,cAAc,CAAC;IAC/B,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B,CAAC;AAEF;;;GAGG;AACH,wBAAgB,2BAA2B,CACzC,KAAK,EAAE,gCAAgC,GACtC,sBAAsB,GAAG,IAAI,CA4B/B"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { parseAssessmentOrThrow
|
|
1
|
+
import { parseAssessmentOrThrow } from "@mergesignal/contracts";
|
|
2
|
+
import { toPublicPresentation } from "../../assessmentPresentationUtils.js";
|
|
2
3
|
import { deriveScanNarrative } from "../../deriveScanNarrative.js";
|
|
3
4
|
import { buildProfileFromAssessment } from "../profile/buildProfileFromAssessment.js";
|
|
4
5
|
/**
|
|
@@ -11,12 +12,18 @@ export function buildScanPresentationBundle(input) {
|
|
|
11
12
|
const assessment = input.result.assessment;
|
|
12
13
|
if (!assessment)
|
|
13
14
|
return null;
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
let normalized;
|
|
16
|
+
try {
|
|
17
|
+
normalized = parseAssessmentOrThrow(assessment);
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
const presentation = toPublicPresentation(normalized.presentation);
|
|
23
|
+
const profile = buildProfileFromAssessment(normalized, presentation, input.result);
|
|
17
24
|
const facts = deriveScanNarrative(input.result);
|
|
18
25
|
return {
|
|
19
|
-
assessment,
|
|
26
|
+
assessment: normalized,
|
|
20
27
|
presentation,
|
|
21
28
|
profile,
|
|
22
29
|
facts,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"buildScanPresentationBundle.test.d.ts","sourceRoot":"","sources":["../../../src/presentation/orchestration/buildScanPresentationBundle.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { parseAssessmentOrThrow } from "@mergesignal/contracts";
|
|
2
|
+
import { describe, expect, it } from "vitest";
|
|
3
|
+
import { assessmentTypescriptPatch } from "../../fixtures/assessmentFixtures.js";
|
|
4
|
+
import { buildScanCardPresentation } from "./buildScanCardPresentation.js";
|
|
5
|
+
import { buildScanPresentationBundle } from "./buildScanPresentationBundle.js";
|
|
6
|
+
const abi1Assessment = {
|
|
7
|
+
posture: "safe",
|
|
8
|
+
confidence: "high",
|
|
9
|
+
primaryConcern: null,
|
|
10
|
+
concerns: [],
|
|
11
|
+
factors: ["tooling_maintenance"],
|
|
12
|
+
changeClasses: ["tooling_maintenance"],
|
|
13
|
+
presentation: {
|
|
14
|
+
narrativeIntensity: "minimal",
|
|
15
|
+
reachVisibility: "hidden",
|
|
16
|
+
verificationIntensity: "advisory",
|
|
17
|
+
insightEmissionFloor: "none",
|
|
18
|
+
reportMode: "high_signal_pr",
|
|
19
|
+
},
|
|
20
|
+
};
|
|
21
|
+
function minimalScanResult(assessment) {
|
|
22
|
+
return {
|
|
23
|
+
totalScore: 42,
|
|
24
|
+
layerScores: {
|
|
25
|
+
security: 10,
|
|
26
|
+
maintainability: 20,
|
|
27
|
+
ecosystem: 30,
|
|
28
|
+
upgradeImpact: 40,
|
|
29
|
+
},
|
|
30
|
+
findings: [],
|
|
31
|
+
generatedAt: "2026-01-01T00:00:00.000Z",
|
|
32
|
+
decision: {
|
|
33
|
+
recommendation: "safe",
|
|
34
|
+
confidence: "high",
|
|
35
|
+
reasoning: [],
|
|
36
|
+
},
|
|
37
|
+
assessment,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
describe("buildScanPresentationBundle (presentation boundary)", () => {
|
|
41
|
+
it("ABI-2 assessment produces a bundle", () => {
|
|
42
|
+
const result = minimalScanResult(assessmentTypescriptPatch);
|
|
43
|
+
const bundle = buildScanPresentationBundle({
|
|
44
|
+
result,
|
|
45
|
+
pipelineStatus: "done",
|
|
46
|
+
});
|
|
47
|
+
expect(bundle).not.toBeNull();
|
|
48
|
+
expect(bundle.assessment.reviewFocalPoint.anchors).toContain("typescript");
|
|
49
|
+
});
|
|
50
|
+
it("ABI-2 assessment renders a dashboard card headline", () => {
|
|
51
|
+
const result = minimalScanResult(assessmentTypescriptPatch);
|
|
52
|
+
const card = buildScanCardPresentation({
|
|
53
|
+
pipelineStatus: "done",
|
|
54
|
+
result,
|
|
55
|
+
});
|
|
56
|
+
expect(card.headline.length).toBeGreaterThan(0);
|
|
57
|
+
});
|
|
58
|
+
it("ABI-1 assessment returns null without throwing", () => {
|
|
59
|
+
const result = minimalScanResult(abi1Assessment);
|
|
60
|
+
expect(() => buildScanPresentationBundle({
|
|
61
|
+
result,
|
|
62
|
+
pipelineStatus: "done",
|
|
63
|
+
})).not.toThrow();
|
|
64
|
+
expect(buildScanPresentationBundle({
|
|
65
|
+
result,
|
|
66
|
+
pipelineStatus: "done",
|
|
67
|
+
})).toBeNull();
|
|
68
|
+
});
|
|
69
|
+
it("ABI-1 assessment does not mutate stored assessment JSON", () => {
|
|
70
|
+
const result = minimalScanResult(structuredClone(abi1Assessment));
|
|
71
|
+
const before = JSON.stringify(result.assessment);
|
|
72
|
+
buildScanPresentationBundle({ result, pipelineStatus: "done" });
|
|
73
|
+
expect(JSON.stringify(result.assessment)).toBe(before);
|
|
74
|
+
expect(result.assessment).not.toHaveProperty("reviewFocalPoint");
|
|
75
|
+
});
|
|
76
|
+
it("ABI-1 direct parseAssessmentOrThrow still throws (contracts strict)", () => {
|
|
77
|
+
expect(() => parseAssessmentOrThrow(abi1Assessment)).toThrow();
|
|
78
|
+
});
|
|
79
|
+
it("mixed PR index: ABI-2 ok and ABI-1 degraded without throw", () => {
|
|
80
|
+
const abi2 = minimalScanResult(assessmentTypescriptPatch);
|
|
81
|
+
const abi1 = minimalScanResult(abi1Assessment);
|
|
82
|
+
for (const result of [abi2, abi1]) {
|
|
83
|
+
expect(() => buildScanCardPresentation({
|
|
84
|
+
pipelineStatus: "done",
|
|
85
|
+
result,
|
|
86
|
+
})).not.toThrow();
|
|
87
|
+
}
|
|
88
|
+
const abi2Card = buildScanCardPresentation({
|
|
89
|
+
pipelineStatus: "done",
|
|
90
|
+
result: abi2,
|
|
91
|
+
});
|
|
92
|
+
const abi1Card = buildScanCardPresentation({
|
|
93
|
+
pipelineStatus: "done",
|
|
94
|
+
result: abi1,
|
|
95
|
+
});
|
|
96
|
+
expect(abi2Card.headline.length).toBeGreaterThan(0);
|
|
97
|
+
expect(abi1Card.pipeline?.status).toBe("failed");
|
|
98
|
+
});
|
|
99
|
+
});
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Assessment, AssessmentPresentationPublic } from "
|
|
1
|
+
import type { Assessment, AssessmentPresentationPublic } from "@mergesignal/contracts";
|
|
2
2
|
import type { ScanNarrativeFacts } from "../../scanNarrativeFacts.js";
|
|
3
3
|
import type { ScanResult } from "../../types.js";
|
|
4
4
|
import type { PresentationProfile } from "../profile/presentationProfile.js";
|