@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.
Files changed (67) hide show
  1. package/dist/affectedAreaLinkage.d.ts +14 -0
  2. package/dist/affectedAreaLinkage.d.ts.map +1 -0
  3. package/dist/affectedAreaLinkage.js +100 -0
  4. package/dist/assessmentLabels.d.ts +1 -1
  5. package/dist/assessmentLabels.d.ts.map +1 -1
  6. package/dist/assessmentPresentationUtils.d.ts +6 -0
  7. package/dist/assessmentPresentationUtils.d.ts.map +1 -0
  8. package/dist/assessmentPresentationUtils.js +17 -0
  9. package/dist/assessmentProjection.d.ts +2 -2
  10. package/dist/assessmentProjection.d.ts.map +1 -1
  11. package/dist/assessmentProjection.js +42 -13
  12. package/dist/deriveScanNarrative.d.ts.map +1 -1
  13. package/dist/deriveScanNarrative.js +92 -9
  14. package/dist/deriveScanNarrative.test.js +74 -0
  15. package/dist/engineWireRegression.test.js +1 -1
  16. package/dist/fixtures/assessmentFixtures.d.ts +2 -1
  17. package/dist/fixtures/assessmentFixtures.d.ts.map +1 -1
  18. package/dist/fixtures/assessmentFixtures.js +78 -23
  19. package/dist/fixtures/assessmentScopeFixtures.d.ts +17 -0
  20. package/dist/fixtures/assessmentScopeFixtures.d.ts.map +1 -0
  21. package/dist/fixtures/assessmentScopeFixtures.js +42 -0
  22. package/dist/formatCardExposureDisplay.d.ts +5 -3
  23. package/dist/formatCardExposureDisplay.d.ts.map +1 -1
  24. package/dist/formatCardExposureDisplay.js +12 -5
  25. package/dist/formatCardExposureDisplay.test.js +9 -1
  26. package/dist/index.d.ts +2 -1
  27. package/dist/index.d.ts.map +1 -1
  28. package/dist/index.js +2 -1
  29. package/dist/presentation/buildGitHubCheckRunOutput.test.js +16 -41
  30. package/dist/presentation/compose/narrativeChannels.js +1 -1
  31. package/dist/presentation/dto/assessmentPresentationFields.d.ts +1 -2
  32. package/dist/presentation/dto/assessmentPresentationFields.d.ts.map +1 -1
  33. package/dist/presentation/fixtures/scanResultFixtures.d.ts.map +1 -1
  34. package/dist/presentation/fixtures/scanResultFixtures.js +19 -1
  35. package/dist/presentation/orchestration/buildScanPresentationBundle.d.ts.map +1 -1
  36. package/dist/presentation/orchestration/buildScanPresentationBundle.js +12 -5
  37. package/dist/presentation/orchestration/buildScanPresentationBundle.test.d.ts +2 -0
  38. package/dist/presentation/orchestration/buildScanPresentationBundle.test.d.ts.map +1 -0
  39. package/dist/presentation/orchestration/buildScanPresentationBundle.test.js +99 -0
  40. package/dist/presentation/orchestration/scanPresentationBundle.d.ts +1 -1
  41. package/dist/presentation/orchestration/scanPresentationBundle.d.ts.map +1 -1
  42. package/dist/presentation/presentation.test.js +1 -1
  43. package/dist/presentation/presentationPersonas.test.js +0 -5
  44. package/dist/presentation/profile/buildProfileFromAssessment.d.ts +1 -1
  45. package/dist/presentation/profile/buildProfileFromAssessment.d.ts.map +1 -1
  46. package/dist/presentation/profile/buildProfileFromAssessment.js +13 -2
  47. package/dist/presentation/surfaceParity.test.js +73 -5
  48. package/dist/repoIntelligenceSchema.d.ts +3 -3
  49. package/dist/riskSignals.d.ts +19 -0
  50. package/dist/riskSignals.d.ts.map +1 -0
  51. package/dist/riskSignals.js +32 -0
  52. package/dist/scanNarrativeFacts.d.ts +25 -7
  53. package/dist/scanNarrativeFacts.d.ts.map +1 -1
  54. package/dist/scanNarrativeFacts.js +4 -1
  55. package/dist/scanPresentationBundle.golden.test.d.ts +2 -0
  56. package/dist/scanPresentationBundle.golden.test.d.ts.map +1 -0
  57. package/dist/scanPresentationBundle.golden.test.js +78 -0
  58. package/dist/scanResultSchema.d.ts +53 -4
  59. package/dist/scanResultSchema.d.ts.map +1 -1
  60. package/dist/scanResultSchema.js +1 -1
  61. package/dist/scanResultSchema.test.js +26 -0
  62. package/dist/types.d.ts +1 -1
  63. package/dist/types.d.ts.map +1 -1
  64. package/package.json +4 -2
  65. package/dist/assessmentSchema.d.ts +0 -155
  66. package/dist/assessmentSchema.d.ts.map +0 -1
  67. 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
- export const assessmentPrettier = {
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
- export const assessmentEslint = {
32
+ }, {
33
+ reviewFocalPoint: minimalReviewFocalPoint(["prettier"]),
34
+ reachScope: emptyReachScope(),
35
+ verificationScope: emptyVerificationScope(),
36
+ });
37
+ export const assessmentEslint = withAssessmentScope({
29
38
  ...assessmentTypescriptPatch,
30
- };
31
- export const assessmentVitest = {
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
- export const assessmentFastifyRuntime = {
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
- export const assessmentBullmq = {
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
- export const assessmentNextAuth = {
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
- export const assessmentMixedTypescriptFastify = {
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: ["confirmed_runtime_usage", "http_framework_infrastructure"],
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
- export const assessmentLimitedContext = {
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
- export const assessmentStub = {
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
- export const assessmentUnknownSafe = {
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
- * Dashboard card exposure semantics display-only interpretation of totalScore.
3
- * Not persisted; not an engine output; complements merge posture (Safe / Review / Risky).
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 totalScore to a fixed exposure category (card UX only). */
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,0EAA0E;AAC1E,wBAAgB,yBAAyB,CACvC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAC/B,mBAAmB,GAAG,IAAI,CAM5B;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
+ {"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
- * Dashboard card exposure semantics display-only interpretation of totalScore.
3
- * Not persisted; not an engine output; complements merge posture (Safe / Review / Risky).
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 totalScore to a fixed exposure category (card UX only). */
35
- export function deriveCardExposureDisplay(score) {
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
- const category = EXPOSURE_ORDER[idx >= 0 ? idx : EXPOSURE_ORDER.length - 1];
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
@@ -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,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"}
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
- posture: "safe",
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
- const needsReviewAssessment = {
41
- posture: "needs_review",
42
- confidence: "medium",
43
- primaryConcern: "confirmed_runtime_usage",
44
- concerns: [
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, result, profile.status),
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 "../../assessmentSchema.js";
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,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAClE,OAAO,KAAK,EACV,kBAAkB,EAClB,eAAe,EAEhB,MAAM,2BAA2B,CAAC;AAEnC,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
+ {"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,UAiCtC,CAAC;AAEF,eAAO,MAAM,yBAAyB,EAAE,UA2BvC,CAAC;AAEF,eAAO,MAAM,wBAAwB,EAAE,UA4BtC,CAAC"}
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":"AAKA,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,CAsB/B"}
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, toPublicPresentation, } from "../../assessmentSchema.js";
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
- parseAssessmentOrThrow(assessment);
15
- const presentation = toPublicPresentation(assessment.presentation);
16
- const profile = buildProfileFromAssessment(assessment, presentation, input.result);
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,2 @@
1
+ export {};
2
+ //# sourceMappingURL=buildScanPresentationBundle.test.d.ts.map
@@ -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 "../../assessmentSchema.js";
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";