@mergesignal/shared 0.12.2 → 0.13.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 (172) hide show
  1. package/dist/assessment/authoredCommunication.d.ts +30 -0
  2. package/dist/assessment/authoredCommunication.d.ts.map +1 -0
  3. package/dist/assessment/authoredCommunication.js +18 -0
  4. package/dist/assessment/index.d.ts +6 -0
  5. package/dist/assessment/index.d.ts.map +1 -0
  6. package/dist/assessment/index.js +5 -0
  7. package/dist/assessment/literals.d.ts +44 -0
  8. package/dist/assessment/literals.d.ts.map +1 -0
  9. package/dist/assessment/literals.js +140 -0
  10. package/dist/assessment/schema.d.ts +311 -0
  11. package/dist/assessment/schema.d.ts.map +1 -0
  12. package/dist/assessment/schema.js +162 -0
  13. package/dist/assessment/types.d.ts +197 -0
  14. package/dist/assessment/types.d.ts.map +1 -0
  15. package/dist/assessment/types.js +1 -0
  16. package/dist/assessment/version.d.ts +11 -0
  17. package/dist/assessment/version.d.ts.map +1 -0
  18. package/dist/assessment/version.js +9 -0
  19. package/dist/assessmentLabels.d.ts +1 -1
  20. package/dist/assessmentLabels.d.ts.map +1 -1
  21. package/dist/assessmentPresentationUtils.d.ts +1 -1
  22. package/dist/assessmentPresentationUtils.d.ts.map +1 -1
  23. package/dist/assessmentProjection.d.ts +1 -1
  24. package/dist/assessmentProjection.d.ts.map +1 -1
  25. package/dist/deriveScanNarrative.d.ts.map +1 -1
  26. package/dist/deriveScanNarrative.js +2 -1
  27. package/dist/fixtures/assessmentFixtures.d.ts +1 -1
  28. package/dist/fixtures/assessmentScopeFixtures.d.ts +1 -1
  29. package/dist/index.d.ts +2 -0
  30. package/dist/index.d.ts.map +1 -1
  31. package/dist/index.js +2 -0
  32. package/dist/lockfileEvidence.d.ts +22 -0
  33. package/dist/lockfileEvidence.d.ts.map +1 -0
  34. package/dist/lockfileEvidence.js +32 -0
  35. package/dist/presentation/dto/assessmentPresentationFields.d.ts +1 -1
  36. package/dist/presentation/dto/assessmentPresentationFields.d.ts.map +1 -1
  37. package/dist/presentation/orchestration/buildScanPresentationBundle.d.ts.map +1 -1
  38. package/dist/presentation/orchestration/buildScanPresentationBundle.js +2 -1
  39. package/dist/presentation/orchestration/scanPresentationBundle.d.ts +2 -1
  40. package/dist/presentation/orchestration/scanPresentationBundle.d.ts.map +1 -1
  41. package/dist/presentation/profile/buildProfileFromAssessment.d.ts +1 -1
  42. package/dist/presentation/profile/buildProfileFromAssessment.d.ts.map +1 -1
  43. package/dist/presentation/profile/buildProfileFromAssessment.js +13 -5
  44. package/dist/repoIntelligenceSchema.d.ts +5 -5
  45. package/dist/scanResultSchema.d.ts +6 -6
  46. package/dist/scanResultSchema.js +1 -1
  47. package/dist/types.d.ts +6 -2
  48. package/dist/types.d.ts.map +1 -1
  49. package/package.json +1 -2
  50. package/dist/actionsStepSummary.test.d.ts +0 -2
  51. package/dist/actionsStepSummary.test.d.ts.map +0 -1
  52. package/dist/actionsStepSummary.test.js +0 -53
  53. package/dist/assessmentProjection.verificationChannel.test.d.ts +0 -2
  54. package/dist/assessmentProjection.verificationChannel.test.d.ts.map +0 -1
  55. package/dist/assessmentProjection.verificationChannel.test.js +0 -110
  56. package/dist/deriveScanNarrative.test.d.ts +0 -2
  57. package/dist/deriveScanNarrative.test.d.ts.map +0 -1
  58. package/dist/deriveScanNarrative.test.js +0 -274
  59. package/dist/engineWireRegression.test.d.ts +0 -2
  60. package/dist/engineWireRegression.test.d.ts.map +0 -1
  61. package/dist/engineWireRegression.test.js +0 -77
  62. package/dist/fixtures/engineAbi4Fixtures.d.ts +0 -16
  63. package/dist/fixtures/engineAbi4Fixtures.d.ts.map +0 -1
  64. package/dist/fixtures/engineAbi4Fixtures.js +0 -26
  65. package/dist/fixtures/legacyEngineRepoIntelligence.d.ts +0 -28
  66. package/dist/fixtures/legacyEngineRepoIntelligence.d.ts.map +0 -1
  67. package/dist/fixtures/legacyEngineRepoIntelligence.js +0 -28
  68. package/dist/fixtures/repoIntelligenceFixtures.d.ts +0 -8
  69. package/dist/fixtures/repoIntelligenceFixtures.d.ts.map +0 -1
  70. package/dist/fixtures/repoIntelligenceFixtures.js +0 -123
  71. package/dist/fixtures/repoIntelligenceTestHelpers.d.ts +0 -5
  72. package/dist/fixtures/repoIntelligenceTestHelpers.d.ts.map +0 -1
  73. package/dist/fixtures/repoIntelligenceTestHelpers.js +0 -28
  74. package/dist/formatInsight.test.d.ts +0 -2
  75. package/dist/formatInsight.test.d.ts.map +0 -1
  76. package/dist/formatInsight.test.js +0 -102
  77. package/dist/narrativeParity.test.d.ts +0 -2
  78. package/dist/narrativeParity.test.d.ts.map +0 -1
  79. package/dist/narrativeParity.test.js +0 -35
  80. package/dist/narrativePresentation.test.d.ts +0 -2
  81. package/dist/narrativePresentation.test.d.ts.map +0 -1
  82. package/dist/narrativePresentation.test.js +0 -54
  83. package/dist/normalizeGeneratedText.test.d.ts +0 -2
  84. package/dist/normalizeGeneratedText.test.d.ts.map +0 -1
  85. package/dist/normalizeGeneratedText.test.js +0 -18
  86. package/dist/prRiskBand.test.d.ts +0 -2
  87. package/dist/prRiskBand.test.d.ts.map +0 -1
  88. package/dist/prRiskBand.test.js +0 -68
  89. package/dist/prRiskWire.test.d.ts +0 -2
  90. package/dist/prRiskWire.test.d.ts.map +0 -1
  91. package/dist/prRiskWire.test.js +0 -106
  92. package/dist/prRiskWiringRegression.test.d.ts +0 -2
  93. package/dist/prRiskWiringRegression.test.d.ts.map +0 -1
  94. package/dist/prRiskWiringRegression.test.js +0 -102
  95. package/dist/presentation/abi3Expression.test.d.ts +0 -13
  96. package/dist/presentation/abi3Expression.test.d.ts.map +0 -1
  97. package/dist/presentation/abi3Expression.test.js +0 -392
  98. package/dist/presentation/buildGitHubCheckRunOutput.test.d.ts +0 -2
  99. package/dist/presentation/buildGitHubCheckRunOutput.test.d.ts.map +0 -1
  100. package/dist/presentation/buildGitHubCheckRunOutput.test.js +0 -163
  101. package/dist/presentation/bundleAccessorParity.test.d.ts +0 -9
  102. package/dist/presentation/bundleAccessorParity.test.d.ts.map +0 -1
  103. package/dist/presentation/bundleAccessorParity.test.js +0 -126
  104. package/dist/presentation/cliParity.test.d.ts +0 -2
  105. package/dist/presentation/cliParity.test.d.ts.map +0 -1
  106. package/dist/presentation/cliParity.test.js +0 -49
  107. package/dist/presentation/compose/narrativeChannels.test.d.ts +0 -2
  108. package/dist/presentation/compose/narrativeChannels.test.d.ts.map +0 -1
  109. package/dist/presentation/compose/narrativeChannels.test.js +0 -42
  110. package/dist/presentation/decisionSurface.test.d.ts +0 -2
  111. package/dist/presentation/decisionSurface.test.d.ts.map +0 -1
  112. package/dist/presentation/decisionSurface.test.js +0 -290
  113. package/dist/presentation/fixtures/dashboardCardGolden.test.d.ts +0 -2
  114. package/dist/presentation/fixtures/dashboardCardGolden.test.d.ts.map +0 -1
  115. package/dist/presentation/fixtures/dashboardCardGolden.test.js +0 -38
  116. package/dist/presentation/fixtures/presentationPersonaFixtures.d.ts +0 -11
  117. package/dist/presentation/fixtures/presentationPersonaFixtures.d.ts.map +0 -1
  118. package/dist/presentation/fixtures/presentationPersonaFixtures.js +0 -208
  119. package/dist/presentation/fixtures/scanResultFixtures.d.ts +0 -5
  120. package/dist/presentation/fixtures/scanResultFixtures.d.ts.map +0 -1
  121. package/dist/presentation/fixtures/scanResultFixtures.js +0 -123
  122. package/dist/presentation/intent/postureVocabularyGuard.test.d.ts +0 -2
  123. package/dist/presentation/intent/postureVocabularyGuard.test.d.ts.map +0 -1
  124. package/dist/presentation/intent/postureVocabularyGuard.test.js +0 -23
  125. package/dist/presentation/orchestration/buildScanPresentationBundle.test.d.ts +0 -2
  126. package/dist/presentation/orchestration/buildScanPresentationBundle.test.d.ts.map +0 -1
  127. package/dist/presentation/orchestration/buildScanPresentationBundle.test.js +0 -99
  128. package/dist/presentation/presentation.test.d.ts +0 -2
  129. package/dist/presentation/presentation.test.d.ts.map +0 -1
  130. package/dist/presentation/presentation.test.js +0 -126
  131. package/dist/presentation/presentationPersonas.test.d.ts +0 -2
  132. package/dist/presentation/presentationPersonas.test.d.ts.map +0 -1
  133. package/dist/presentation/presentationPersonas.test.js +0 -164
  134. package/dist/presentation/surfaceParity.test.d.ts +0 -2
  135. package/dist/presentation/surfaceParity.test.d.ts.map +0 -1
  136. package/dist/presentation/surfaceParity.test.js +0 -156
  137. package/dist/presentation/verificationChannelParity.test.d.ts +0 -2
  138. package/dist/presentation/verificationChannelParity.test.d.ts.map +0 -1
  139. package/dist/presentation/verificationChannelParity.test.js +0 -57
  140. package/dist/productMessaging.test.d.ts +0 -2
  141. package/dist/productMessaging.test.d.ts.map +0 -1
  142. package/dist/productMessaging.test.js +0 -97
  143. package/dist/repoIntelligenceSchema.contract.test.d.ts +0 -2
  144. package/dist/repoIntelligenceSchema.contract.test.d.ts.map +0 -1
  145. package/dist/repoIntelligenceSchema.contract.test.js +0 -51
  146. package/dist/repoIntelligenceSemantics.test.d.ts +0 -2
  147. package/dist/repoIntelligenceSemantics.test.d.ts.map +0 -1
  148. package/dist/repoIntelligenceSemantics.test.js +0 -63
  149. package/dist/repoIntelligenceValidation.persist.test.d.ts +0 -2
  150. package/dist/repoIntelligenceValidation.persist.test.d.ts.map +0 -1
  151. package/dist/repoIntelligenceValidation.persist.test.js +0 -44
  152. package/dist/riskSignals.test.d.ts +0 -2
  153. package/dist/riskSignals.test.d.ts.map +0 -1
  154. package/dist/riskSignals.test.js +0 -32
  155. package/dist/riskVocabulary.test.d.ts +0 -2
  156. package/dist/riskVocabulary.test.d.ts.map +0 -1
  157. package/dist/riskVocabulary.test.js +0 -14
  158. package/dist/scanPresentationBundle.golden.test.d.ts +0 -2
  159. package/dist/scanPresentationBundle.golden.test.d.ts.map +0 -1
  160. package/dist/scanPresentationBundle.golden.test.js +0 -78
  161. package/dist/scanResultSchema.test.d.ts +0 -2
  162. package/dist/scanResultSchema.test.d.ts.map +0 -1
  163. package/dist/scanResultSchema.test.js +0 -162
  164. package/dist/scanSurfaceCopy.test.d.ts +0 -2
  165. package/dist/scanSurfaceCopy.test.d.ts.map +0 -1
  166. package/dist/scanSurfaceCopy.test.js +0 -14
  167. package/dist/selectTopAffectedAreas.test.d.ts +0 -2
  168. package/dist/selectTopAffectedAreas.test.d.ts.map +0 -1
  169. package/dist/selectTopAffectedAreas.test.js +0 -179
  170. package/dist/trustedScanGuards.test.d.ts +0 -2
  171. package/dist/trustedScanGuards.test.d.ts.map +0 -1
  172. package/dist/trustedScanGuards.test.js +0 -151
@@ -1,392 +0,0 @@
1
- /**
2
- * Wave 2.D — ABI 3 expression validation.
3
- *
4
- * Validates that:
5
- * 1. projectReasoningLines reads from assessment.reasoning (ABI 3) when present
6
- * 2. projectVerificationActions returns assessment.verificationScope.guidance when present
7
- * 3. PR comment includes reviewFocalPoint.electionSummary when present
8
- * 4. Check run "Why" section uses assessment.reasoning lines directly
9
- * 5. No prohibited vocabulary appears in rendered surfaces
10
- * 6. assessment.reasoning takes priority over decision.reasoning
11
- */
12
- import { describe, expect, it } from "vitest";
13
- import { minimalReviewFocalPoint, reachScopeFor, verificationScopeFor, withAssessmentScope, } from "../fixtures/assessmentScopeFixtures.js";
14
- import { projectReasoningLines, projectVerificationActions, } from "../assessmentProjection.js";
15
- import { toPublicPresentation } from "../assessmentPresentationUtils.js";
16
- import { projectAssessmentFields } from "./projectAssessmentFields.js";
17
- import { buildScanPresentationBundle } from "./orchestration/buildScanPresentationBundle.js";
18
- import { presentGitHubPrComment } from "./presenters/presentGitHubPrComment.js";
19
- import { presentGitHubCheckRun } from "./presenters/presentGitHubCheckRun.js";
20
- import { buildGitHubCheckRunOutput } from "./buildGitHubCheckRunOutput.js";
21
- import { presentGitHubPrCommentMarkdownFromResult } from "../presentGitHubPrComment.js";
22
- // ---------------------------------------------------------------------------
23
- // ABI 3 — Canonical express/confirmed_runtime_usage fixture
24
- // ---------------------------------------------------------------------------
25
- const expressReasoning = [
26
- "express is used in HTTP request handling in this repository via middleware chains.",
27
- "Import paths to application entry points were directly observed.",
28
- "Verification is required: review HTTP route definitions and middleware implementation.",
29
- ];
30
- const expressGuidance = [
31
- "Review HTTP route definitions and middleware implementation in src/app.ts and src/server.ts.",
32
- "Review handler implementations that use express routing.",
33
- ];
34
- const expressElectionSummary = "express was selected as the primary review anchor because it has the highest repository reach among changed packages and confirmed runtime usage in HTTP request handling.";
35
- const assessmentExpressAbi3 = withAssessmentScope({
36
- posture: "needs_review",
37
- confidence: "high",
38
- primaryConcern: "confirmed_runtime_usage",
39
- concerns: [
40
- {
41
- kind: "confirmed_runtime_usage",
42
- rank: 1,
43
- packages: ["express"],
44
- evidenceRefs: ["fixture:express"],
45
- context: "express participates in HTTP request handling across 12 files.",
46
- },
47
- ],
48
- factors: ["confirmed_runtime_usage", "http_framework_infrastructure"],
49
- changeClasses: ["runtime_upgrade"],
50
- presentation: {
51
- narrativeIntensity: "elevated",
52
- reachVisibility: "prominent",
53
- verificationIntensity: "required",
54
- insightEmissionFloor: "full",
55
- reportMode: "high_signal_pr",
56
- },
57
- reasoning: expressReasoning,
58
- confidenceRationale: "Confidence is high: propagation from express to application entry points was directly observed.",
59
- }, {
60
- reviewFocalPoint: {
61
- ...minimalReviewFocalPoint(["express"]),
62
- electionSummary: expressElectionSummary,
63
- },
64
- reachScope: reachScopeFor(["express"], "high"),
65
- verificationScope: verificationScopeFor(["express"], ["routes", "middleware"], undefined),
66
- });
67
- const assessmentExpressAbi3WithGuidance = {
68
- ...assessmentExpressAbi3,
69
- verificationScope: {
70
- ...assessmentExpressAbi3.verificationScope,
71
- guidance: expressGuidance,
72
- },
73
- };
74
- function scanResultWithAssessment(assessment, overrides = {}) {
75
- return {
76
- totalScore: 63,
77
- layerScores: {
78
- security: 10,
79
- maintainability: 20,
80
- ecosystem: 30,
81
- upgradeImpact: 15,
82
- },
83
- findings: [],
84
- generatedAt: "2026-01-01T00:00:00.000Z",
85
- changedPackages: ["express"],
86
- assessment,
87
- decision: {
88
- recommendation: "needs_review",
89
- confidence: "high",
90
- reasoning: ["Old generic decision reasoning — should not appear."],
91
- },
92
- ...overrides,
93
- };
94
- }
95
- // ---------------------------------------------------------------------------
96
- // projectReasoningLines — ABI 3 priority
97
- // ---------------------------------------------------------------------------
98
- describe("projectReasoningLines — ABI 3", () => {
99
- it("returns assessment.reasoning when present (ABI 3 takes priority)", () => {
100
- const result = scanResultWithAssessment(assessmentExpressAbi3);
101
- const lines = projectReasoningLines(result);
102
- expect(lines).toEqual(expressReasoning);
103
- });
104
- it("assessment.reasoning takes priority over decision.reasoning", () => {
105
- const result = scanResultWithAssessment(assessmentExpressAbi3);
106
- const lines = projectReasoningLines(result);
107
- expect(lines).not.toContain("Old generic decision reasoning — should not appear.");
108
- });
109
- it("falls back to decision.reasoning when assessment.reasoning is empty", () => {
110
- const assessmentWithoutReasoning = {
111
- ...assessmentExpressAbi3,
112
- reasoning: [],
113
- };
114
- const result = scanResultWithAssessment(assessmentWithoutReasoning);
115
- const lines = projectReasoningLines(result);
116
- expect(lines).toEqual([
117
- "Old generic decision reasoning — should not appear.",
118
- ]);
119
- });
120
- it("returns empty array when both reasoning sources are absent", () => {
121
- const assessmentEmpty = {
122
- ...assessmentExpressAbi3,
123
- reasoning: [],
124
- };
125
- const result = scanResultWithAssessment(assessmentEmpty, {
126
- decision: {
127
- recommendation: "needs_review",
128
- confidence: "high",
129
- reasoning: [],
130
- },
131
- });
132
- const lines = projectReasoningLines(result);
133
- expect(lines).toEqual([]);
134
- });
135
- it("reasoning lines contain no prohibited vocabulary", () => {
136
- const result = scanResultWithAssessment(assessmentExpressAbi3);
137
- const lines = projectReasoningLines(result);
138
- const joined = lines.join(" ");
139
- const prohibited = [
140
- "qualityClass",
141
- "qualityBasis",
142
- "proofFingerprint",
143
- "observationId",
144
- "propagationQualityRank",
145
- "AssessmentEvidenceBundle",
146
- "DenseEvidenceHighlight",
147
- "will affect",
148
- "will break",
149
- "breaks compatibility",
150
- "remain compatible",
151
- "critical path",
152
- ];
153
- for (const term of prohibited) {
154
- expect(joined).not.toContain(term);
155
- }
156
- });
157
- });
158
- // ---------------------------------------------------------------------------
159
- // projectVerificationActions — guidance priority
160
- // ---------------------------------------------------------------------------
161
- describe("projectVerificationActions — ABI 3 guidance", () => {
162
- const presentation = toPublicPresentation(assessmentExpressAbi3WithGuidance.presentation);
163
- it("returns guidance prose when verificationScope.guidance is present", () => {
164
- const result = scanResultWithAssessment(assessmentExpressAbi3WithGuidance);
165
- const actions = projectVerificationActions(assessmentExpressAbi3WithGuidance, presentation, result, 6);
166
- expect(actions).toEqual(expressGuidance);
167
- });
168
- it("guidance respects max limit", () => {
169
- const result = scanResultWithAssessment(assessmentExpressAbi3WithGuidance);
170
- const actions = projectVerificationActions(assessmentExpressAbi3WithGuidance, presentation, result, 1);
171
- expect(actions).toHaveLength(1);
172
- expect(actions[0]).toBe(expressGuidance[0]);
173
- });
174
- it("falls back to focus tokens when guidance is absent", () => {
175
- const result = scanResultWithAssessment(assessmentExpressAbi3);
176
- const actions = projectVerificationActions(assessmentExpressAbi3, presentation, result, 6);
177
- // No guidance — falls back to runtime focus tokens
178
- expect(actions).toEqual(expect.arrayContaining(["routes", "middleware"]));
179
- });
180
- it("returns empty when verificationIntensity is none", () => {
181
- const noneAssessment = {
182
- ...assessmentExpressAbi3WithGuidance,
183
- presentation: {
184
- ...assessmentExpressAbi3WithGuidance.presentation,
185
- verificationIntensity: "none",
186
- },
187
- };
188
- const result = scanResultWithAssessment(noneAssessment);
189
- const actions = projectVerificationActions(noneAssessment, toPublicPresentation(noneAssessment.presentation), result, 6);
190
- expect(actions).toEqual([]);
191
- });
192
- });
193
- // ---------------------------------------------------------------------------
194
- // projectAssessmentFields — ABI 3 expression projection
195
- // ---------------------------------------------------------------------------
196
- describe("projectAssessmentFields — ABI 3 expression", () => {
197
- it("projects confidenceRationale and electionSummary from assessment", () => {
198
- const result = scanResultWithAssessment(assessmentExpressAbi3);
199
- const bundle = buildScanPresentationBundle({
200
- result,
201
- pipelineStatus: "done",
202
- });
203
- const fields = projectAssessmentFields(bundle);
204
- expect(fields.confidenceRationale).toBe("Confidence is high: propagation from express to application entry points was directly observed.");
205
- expect(fields.electionSummary).toBe(expressElectionSummary);
206
- expect(fields.reasoning).toEqual(expressReasoning);
207
- });
208
- it("omits empty confidenceRationale and electionSummary after trim", () => {
209
- const assessment = {
210
- ...assessmentExpressAbi3,
211
- confidenceRationale: " ",
212
- reviewFocalPoint: {
213
- ...assessmentExpressAbi3.reviewFocalPoint,
214
- electionSummary: "",
215
- },
216
- };
217
- const result = scanResultWithAssessment(assessment);
218
- const bundle = buildScanPresentationBundle({
219
- result,
220
- pipelineStatus: "done",
221
- });
222
- const fields = projectAssessmentFields(bundle);
223
- expect(fields.confidenceRationale).toBeUndefined();
224
- expect(fields.electionSummary).toBeUndefined();
225
- });
226
- it("projects reasoning when assessment has concerns", () => {
227
- const result = scanResultWithAssessment(assessmentExpressAbi3);
228
- const bundle = buildScanPresentationBundle({
229
- result,
230
- pipelineStatus: "done",
231
- });
232
- const fields = projectAssessmentFields(bundle);
233
- expect(assessmentExpressAbi3.concerns.length).toBeGreaterThan(0);
234
- expect(fields.reasoning.length).toBeGreaterThan(0);
235
- expect(fields.reasoning).toEqual(expressReasoning);
236
- });
237
- });
238
- // ---------------------------------------------------------------------------
239
- // PR comment — electionSummary and reasoning
240
- // ---------------------------------------------------------------------------
241
- describe("presentGitHubPrComment — ABI 3 expression", () => {
242
- function buildBundle(assessment) {
243
- const result = scanResultWithAssessment(assessment, {
244
- changedPackages: ["express"],
245
- });
246
- return buildScanPresentationBundle({ result, pipelineStatus: "done" });
247
- }
248
- it("introLines include electionSummary when present", () => {
249
- const bundle = buildBundle(assessmentExpressAbi3);
250
- const comment = presentGitHubPrComment(bundle);
251
- expect(comment.introLines).toContain(expressElectionSummary);
252
- });
253
- it("introLines include assessment.reasoning sentences", () => {
254
- const bundle = buildBundle(assessmentExpressAbi3);
255
- const comment = presentGitHubPrComment(bundle);
256
- const joined = comment.introLines.join(" ");
257
- expect(joined).toContain("express is used in HTTP request handling");
258
- expect(joined).toContain("Import paths to application entry points");
259
- });
260
- it("electionSummary is absent from introLines when not set", () => {
261
- const assessmentNoElection = {
262
- ...assessmentExpressAbi3,
263
- reviewFocalPoint: {
264
- ...assessmentExpressAbi3.reviewFocalPoint,
265
- electionSummary: undefined,
266
- },
267
- };
268
- const bundle = buildBundle(assessmentNoElection);
269
- const comment = presentGitHubPrComment(bundle);
270
- expect(comment.introLines).not.toContain(expressElectionSummary);
271
- });
272
- it("introLines contain no prohibited vocabulary", () => {
273
- const bundle = buildBundle(assessmentExpressAbi3);
274
- const comment = presentGitHubPrComment(bundle);
275
- const joined = comment.introLines.join(" ");
276
- const prohibited = [
277
- "qualityClass",
278
- "qualityBasis",
279
- "proofFingerprint",
280
- "observationId",
281
- "propagationQualityRank",
282
- ];
283
- for (const term of prohibited) {
284
- expect(joined).not.toContain(term);
285
- }
286
- });
287
- });
288
- // ---------------------------------------------------------------------------
289
- // Check run — Why section uses assessment.reasoning
290
- // ---------------------------------------------------------------------------
291
- describe("presentGitHubCheckRun — ABI 3 Why section", () => {
292
- const SCAN_ID = "scan-abi3-test";
293
- const ORIGIN = "https://app.test";
294
- function buildBundle(assessment) {
295
- const result = scanResultWithAssessment(assessment, {
296
- changedPackages: ["express"],
297
- });
298
- return buildScanPresentationBundle({ result, pipelineStatus: "done" });
299
- }
300
- it("Why section bullets come from assessment.reasoning (ABI 3)", () => {
301
- const bundle = buildBundle(assessmentExpressAbi3);
302
- const checkRun = presentGitHubCheckRun(bundle, {
303
- scanId: SCAN_ID,
304
- webAppOrigin: ORIGIN,
305
- });
306
- const whySection = checkRun.sections.find((s) => s.id === "why" && s.title === "Why");
307
- expect(whySection).toBeDefined();
308
- expect(whySection.bullets).toEqual(expect.arrayContaining([
309
- "express is used in HTTP request handling in this repository via middleware chains.",
310
- ]));
311
- });
312
- it("Why section does not contain old generic decision reasoning", () => {
313
- const bundle = buildBundle(assessmentExpressAbi3);
314
- const checkRun = presentGitHubCheckRun(bundle, {
315
- scanId: SCAN_ID,
316
- webAppOrigin: ORIGIN,
317
- });
318
- const whySection = checkRun.sections.find((s) => s.id === "why" && s.title === "Why");
319
- const bulletText = whySection?.bullets.join(" ") ?? "";
320
- expect(bulletText).not.toContain("Old generic decision reasoning");
321
- });
322
- it("check run summary contains no prohibited vocabulary", () => {
323
- const result = scanResultWithAssessment(assessmentExpressAbi3, {
324
- changedPackages: ["express"],
325
- methodologyVersion: "mergesignal-engine/test",
326
- });
327
- const output = buildGitHubCheckRunOutput(result, {
328
- scanId: SCAN_ID,
329
- webAppOrigin: ORIGIN,
330
- });
331
- const prohibited = [
332
- "qualityClass",
333
- "qualityBasis",
334
- "proofFingerprint",
335
- "observationId",
336
- "propagationQualityRank",
337
- "AssessmentEvidenceBundle",
338
- ];
339
- for (const term of prohibited) {
340
- expect(output.summary).not.toContain(term);
341
- }
342
- });
343
- it("Why section respects 3-line limit", () => {
344
- const bundle = buildBundle(assessmentExpressAbi3);
345
- const checkRun = presentGitHubCheckRun(bundle, {
346
- scanId: SCAN_ID,
347
- webAppOrigin: ORIGIN,
348
- });
349
- const whySection = checkRun.sections.find((s) => s.title === "Why");
350
- if (whySection) {
351
- expect(whySection.bullets.length).toBeLessThanOrEqual(3);
352
- }
353
- });
354
- });
355
- // ---------------------------------------------------------------------------
356
- // End-to-end markdown snapshot — PR comment with ABI 3 fixture
357
- // ---------------------------------------------------------------------------
358
- describe("PR comment markdown — ABI 3 end-to-end", () => {
359
- it("rendered markdown includes repository-specific reasoning", () => {
360
- const result = scanResultWithAssessment(assessmentExpressAbi3, {
361
- changedPackages: ["express"],
362
- });
363
- const markdown = presentGitHubPrCommentMarkdownFromResult(result);
364
- expect(markdown).toContain("express is used in HTTP request handling");
365
- expect(markdown).toContain("Import paths to application entry points");
366
- });
367
- it("rendered markdown includes electionSummary", () => {
368
- const result = scanResultWithAssessment(assessmentExpressAbi3, {
369
- changedPackages: ["express"],
370
- });
371
- const markdown = presentGitHubPrCommentMarkdownFromResult(result);
372
- expect(markdown).toContain("express was selected as the primary review anchor");
373
- });
374
- it("rendered markdown contains no prohibited vocabulary", () => {
375
- const result = scanResultWithAssessment(assessmentExpressAbi3, {
376
- changedPackages: ["express"],
377
- });
378
- const markdown = presentGitHubPrCommentMarkdownFromResult(result);
379
- const prohibited = [
380
- "qualityClass",
381
- "qualityBasis",
382
- "proofFingerprint",
383
- "observationId",
384
- "propagationQualityRank",
385
- "AssessmentEvidenceBundle",
386
- "DenseEvidenceHighlight",
387
- ];
388
- for (const term of prohibited) {
389
- expect(markdown).not.toContain(term);
390
- }
391
- });
392
- });
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=buildGitHubCheckRunOutput.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"buildGitHubCheckRunOutput.test.d.ts","sourceRoot":"","sources":["../../src/presentation/buildGitHubCheckRunOutput.test.ts"],"names":[],"mappings":""}
@@ -1,163 +0,0 @@
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";
4
- import { buildScanPresentationBundle, presentDashboardCard } from "./index.js";
5
- import { buildGitHubCheckRunOutput } from "./buildGitHubCheckRunOutput.js";
6
- const safeAssessment = assessmentTypescriptPatch;
7
- const baselineAssessment = withAssessmentScope({
8
- posture: "safe",
9
- confidence: "medium",
10
- primaryConcern: "graph_baseline_only",
11
- concerns: [
12
- {
13
- kind: "graph_baseline_only",
14
- rank: 1,
15
- evidenceRefs: ["fixture:baseline"],
16
- },
17
- ],
18
- factors: ["graph_baseline_only"],
19
- changeClasses: ["tooling_maintenance"],
20
- presentation: {
21
- narrativeIntensity: "minimal",
22
- reachVisibility: "hidden",
23
- verificationIntensity: "none",
24
- insightEmissionFloor: "none",
25
- reportMode: "lightweight_pr_graph_baseline",
26
- },
27
- }, {
28
- reviewFocalPoint: minimalReviewFocalPoint(["@types/minimist"]),
29
- reachScope: emptyReachScope(),
30
- verificationScope: emptyVerificationScope(),
31
- });
32
- const needsReviewAssessment = assessmentFastifyRuntime;
33
- const riskyAssessment = withAssessmentScope({
34
- posture: "risky",
35
- confidence: "high",
36
- primaryConcern: "breaking_or_major",
37
- concerns: [
38
- {
39
- kind: "breaking_or_major",
40
- rank: 1,
41
- packages: ["react"],
42
- evidenceRefs: ["fixture:breaking"],
43
- },
44
- ],
45
- factors: ["breaking_or_major"],
46
- changeClasses: ["breaking_change"],
47
- presentation: {
48
- narrativeIntensity: "elevated",
49
- reachVisibility: "prominent",
50
- verificationIntensity: "required",
51
- insightEmissionFloor: "full",
52
- reportMode: "high_signal_pr",
53
- },
54
- }, {
55
- reviewFocalPoint: minimalReviewFocalPoint(["react"]),
56
- reachScope: reachScopeFor(["react"], "high"),
57
- verificationScope: emptyVerificationScope(),
58
- });
59
- function assertNoLegacyCheckRunMarkers(summary) {
60
- expect(summary).not.toContain("Risk index");
61
- expect(summary).not.toContain("Layer scores");
62
- expect(summary).not.toContain("<details>");
63
- expect(summary).not.toMatch(/\d+\/100/);
64
- }
65
- function minimalScanResult(overrides = {}) {
66
- return {
67
- totalScore: 72,
68
- layerScores: {
69
- security: 10,
70
- maintainability: 20,
71
- ecosystem: 30,
72
- upgradeImpact: 15,
73
- },
74
- findings: [],
75
- methodologyVersion: "mergesignal-engine/test",
76
- generatedAt: new Date().toISOString(),
77
- assessment: safeAssessment,
78
- decision: {
79
- recommendation: "safe",
80
- confidence: "medium",
81
- reasoning: [],
82
- },
83
- ...overrides,
84
- };
85
- }
86
- describe("buildGitHubCheckRunOutput", () => {
87
- it("maps safe posture to success conclusion with scan link", () => {
88
- const out = buildGitHubCheckRunOutput(minimalScanResult(), {
89
- scanId: "scan-safe",
90
- webAppOrigin: "https://app.test",
91
- });
92
- expect(out.conclusion).toBe("success");
93
- expect(out.summary).toContain("/scan/scan-safe");
94
- expect(out.summary).toContain("Full scan:");
95
- assertNoLegacyCheckRunMarkers(out.summary);
96
- });
97
- it("maps needs_review posture to neutral conclusion", () => {
98
- const out = buildGitHubCheckRunOutput(minimalScanResult({
99
- assessment: needsReviewAssessment,
100
- decision: {
101
- recommendation: "needs_review",
102
- confidence: "medium",
103
- reasoning: ["Runtime usage confirmed"],
104
- },
105
- changedPackages: ["fastify"],
106
- }), { scanId: "scan-review", webAppOrigin: "https://app.test" });
107
- expect(out.conclusion).toBe("neutral");
108
- expect(out.summary).toContain("/scan/scan-review");
109
- assertNoLegacyCheckRunMarkers(out.summary);
110
- });
111
- it("maps risky posture to failure conclusion", () => {
112
- const out = buildGitHubCheckRunOutput(minimalScanResult({
113
- assessment: riskyAssessment,
114
- decision: {
115
- recommendation: "risky",
116
- confidence: "high",
117
- reasoning: ["Breaking change"],
118
- },
119
- }), { scanId: "scan-risky", webAppOrigin: "https://app.test" });
120
- expect(out.conclusion).toBe("failure");
121
- assertNoLegacyCheckRunMarkers(out.summary);
122
- });
123
- it("produces success conclusion for lightweight baseline presentation", () => {
124
- const out = buildGitHubCheckRunOutput(minimalScanResult({
125
- assessment: baselineAssessment,
126
- reportPresentation: { mode: "lightweight_pr_graph_baseline" },
127
- changedPackages: ["@types/minimist"],
128
- decision: {
129
- recommendation: "safe",
130
- confidence: "medium",
131
- reasoning: [],
132
- },
133
- }), { scanId: "scan-lw", webAppOrigin: "https://app.test" });
134
- expect(out.conclusion).toBe("success");
135
- expect(out.summary).toContain("/scan/scan-lw");
136
- assertNoLegacyCheckRunMarkers(out.summary);
137
- });
138
- it("throws when assessment is missing", () => {
139
- expect(() => buildGitHubCheckRunOutput(minimalScanResult({ assessment: undefined }), "scan-no-assessment")).toThrow(/assessment/i);
140
- });
141
- it("title matches dashboard card headline from the same bundle", () => {
142
- const result = minimalScanResult({
143
- assessment: needsReviewAssessment,
144
- decision: {
145
- recommendation: "needs_review",
146
- confidence: "medium",
147
- reasoning: ["Runtime usage confirmed"],
148
- },
149
- changedPackages: ["fastify"],
150
- });
151
- const out = buildGitHubCheckRunOutput(result, {
152
- scanId: "scan-parity",
153
- webAppOrigin: "https://app.test",
154
- });
155
- const bundle = buildScanPresentationBundle({
156
- result,
157
- pipelineStatus: "done",
158
- });
159
- expect(bundle).not.toBeNull();
160
- const card = presentDashboardCard(bundle);
161
- expect(out.title).toBe(card.headline);
162
- });
163
- });
@@ -1,9 +0,0 @@
1
- /**
2
- * V1 public bundle transport — ScanPresentationBundle vs contracts extractor.
3
- *
4
- * Engine OutcomePresentationBundle uses the same `extractAuthoredCommunication()`
5
- * from `@mergesignal/contracts`; engine-side accessor transport is covered in
6
- * mergesignal-engine `packages/worker/src/outcome-presentation.test.ts`.
7
- */
8
- export {};
9
- //# sourceMappingURL=bundleAccessorParity.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"bundleAccessorParity.test.d.ts","sourceRoot":"","sources":["../../src/presentation/bundleAccessorParity.test.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG"}