@mergesignal/shared 0.11.0 → 0.12.1

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 (55) hide show
  1. package/dist/assessmentProjection.d.ts.map +1 -1
  2. package/dist/assessmentProjection.js +11 -4
  3. package/dist/deriveScanNarrative.d.ts.map +1 -1
  4. package/dist/deriveScanNarrative.js +4 -0
  5. package/dist/fixtures/assessmentScopeFixtures.d.ts +5 -2
  6. package/dist/fixtures/assessmentScopeFixtures.d.ts.map +1 -1
  7. package/dist/fixtures/assessmentScopeFixtures.js +3 -1
  8. package/dist/formatInsight.d.ts +3 -3
  9. package/dist/formatInsight.d.ts.map +1 -1
  10. package/dist/formatInsight.js +0 -9
  11. package/dist/index.d.ts +0 -3
  12. package/dist/index.d.ts.map +1 -1
  13. package/dist/index.js +0 -3
  14. package/dist/prRiskBand.d.ts +7 -0
  15. package/dist/prRiskBand.d.ts.map +1 -1
  16. package/dist/prRiskBand.js +12 -0
  17. package/dist/prRiskBand.test.js +12 -1
  18. package/dist/presentation/abi3Expression.test.d.ts +13 -0
  19. package/dist/presentation/abi3Expression.test.d.ts.map +1 -0
  20. package/dist/presentation/abi3Expression.test.js +392 -0
  21. package/dist/presentation/cliParity.test.d.ts +2 -0
  22. package/dist/presentation/cliParity.test.d.ts.map +1 -0
  23. package/dist/presentation/cliParity.test.js +49 -0
  24. package/dist/presentation/compose/narrativeCompose.d.ts +0 -4
  25. package/dist/presentation/compose/narrativeCompose.d.ts.map +1 -1
  26. package/dist/presentation/compose/narrativeCompose.js +0 -20
  27. package/dist/presentation/dto/assessmentPresentationFields.d.ts +4 -0
  28. package/dist/presentation/dto/assessmentPresentationFields.d.ts.map +1 -1
  29. package/dist/presentation/index.d.ts +1 -1
  30. package/dist/presentation/index.d.ts.map +1 -1
  31. package/dist/presentation/index.js +1 -1
  32. package/dist/presentation/orchestration/buildScanPresentationBundle.d.ts +1 -0
  33. package/dist/presentation/orchestration/buildScanPresentationBundle.d.ts.map +1 -1
  34. package/dist/presentation/orchestration/buildScanPresentationBundle.js +1 -0
  35. package/dist/presentation/presenters/presentCliScanSummary.d.ts.map +1 -1
  36. package/dist/presentation/presenters/presentCliScanSummary.js +9 -7
  37. package/dist/presentation/presenters/presentGitHubCheckRun.d.ts.map +1 -1
  38. package/dist/presentation/presenters/presentGitHubCheckRun.js +20 -15
  39. package/dist/presentation/presenters/presentGitHubPrComment.d.ts.map +1 -1
  40. package/dist/presentation/presenters/presentGitHubPrComment.js +11 -7
  41. package/dist/presentation/presenters/presentScanDetails.d.ts.map +1 -1
  42. package/dist/presentation/presenters/presentScanDetails.js +8 -11
  43. package/dist/presentation/projectAssessmentFields.d.ts.map +1 -1
  44. package/dist/presentation/projectAssessmentFields.js +6 -0
  45. package/dist/presentation/surfaceParity.test.js +8 -0
  46. package/dist/scanResultSchema.d.ts +7 -0
  47. package/dist/scanResultSchema.d.ts.map +1 -1
  48. package/dist/scanResultSchema.test.js +2 -0
  49. package/package.json +1 -1
  50. package/dist/scanDetailViewModelTypes.d.ts +0 -159
  51. package/dist/scanDetailViewModelTypes.d.ts.map +0 -1
  52. package/dist/scanDetailViewModelTypes.js +0 -4
  53. package/dist/truncateCardSummary.d.ts +0 -5
  54. package/dist/truncateCardSummary.d.ts.map +0 -1
  55. package/dist/truncateCardSummary.js +0 -23
@@ -0,0 +1,392 @@
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
+ });
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=cliParity.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cliParity.test.d.ts","sourceRoot":"","sources":["../../src/presentation/cliParity.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,49 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { buildScanPresentationBundle } from "./orchestration/buildScanPresentationBundle.js";
3
+ import { presentCliScanSummary } from "./presenters/presentCliScanSummary.js";
4
+ import { presentDashboardCard } from "./presenters/presentDashboardCard.js";
5
+ import { presentGitHubCheckRun } from "./presenters/presentGitHubCheckRun.js";
6
+ import { presentGitHubPrComment } from "./presenters/presentGitHubPrComment.js";
7
+ import { presentScanDetails } from "./presenters/presentScanDetails.js";
8
+ import { projectAssessmentFields } from "./projectAssessmentFields.js";
9
+ import { scanResultBullmq, scanResultEslint, scanResultFastifyRuntime, scanResultMixedTypescriptFastify, scanResultPrettier, scanResultTypescriptPatch, scanResultVitest, } from "./fixtures/presentationPersonaFixtures.js";
10
+ const SCAN_ID = "22222222-2222-4222-8222-222222222222";
11
+ const ORIGIN = "https://app.example.com";
12
+ const validationPersonas = [
13
+ { name: "mixed-ts-fastify", result: scanResultMixedTypescriptFastify },
14
+ { name: "fastify-runtime", result: scanResultFastifyRuntime },
15
+ { name: "typescript-patch", result: scanResultTypescriptPatch },
16
+ { name: "prettier", result: scanResultPrettier },
17
+ { name: "bullmq", result: scanResultBullmq },
18
+ { name: "eslint", result: scanResultEslint },
19
+ { name: "vitest", result: scanResultVitest },
20
+ ];
21
+ describe("cliParity guardrail", () => {
22
+ for (const persona of validationPersonas) {
23
+ it(`${persona.name}: CLI shares assessment fields with other surfaces`, () => {
24
+ const bundle = buildScanPresentationBundle({
25
+ result: persona.result,
26
+ pipelineStatus: "done",
27
+ });
28
+ const fields = projectAssessmentFields(bundle);
29
+ const cli = presentCliScanSummary(bundle, { repoLabel: "acme/api" });
30
+ const card = presentDashboardCard(bundle);
31
+ const details = presentScanDetails(bundle, { scanId: SCAN_ID });
32
+ const check = presentGitHubCheckRun(bundle, {
33
+ scanId: SCAN_ID,
34
+ webAppOrigin: ORIGIN,
35
+ });
36
+ const comment = presentGitHubPrComment(bundle);
37
+ expect(cli.posture).toBe(fields.posture);
38
+ expect(cli.reasoning).toEqual(fields.reasoning);
39
+ expect(cli.verificationChannel).toBe(fields.verificationChannel);
40
+ expect(cli.verificationFocus).toEqual(fields.verificationFocus);
41
+ expect(cli.confidenceRationale).toBe(fields.confidenceRationale);
42
+ expect(cli.electionSummary).toBe(fields.electionSummary);
43
+ expect(cli.reasoning).toEqual(card.reasoning);
44
+ expect(cli.reasoning).toEqual(details.reasoning);
45
+ expect(cli.reasoning).toEqual(check.reasoning);
46
+ expect(cli.reasoning).toEqual(comment.reasoning);
47
+ });
48
+ }
49
+ });
@@ -5,10 +5,6 @@ export declare function composeSubheadline(bundle: ScanPresentationBundle): stri
5
5
  export declare function composeKeyPoints(bundle: ScanPresentationBundle, max: number): string[];
6
6
  export declare function composeVerificationActions(bundle: ScanPresentationBundle, max: number): string[];
7
7
  export declare function composeAffectedAreaLabels(bundle: ScanPresentationBundle, max: number): string[];
8
- export declare function composeEvidenceRows(bundle: ScanPresentationBundle, max: number): Array<{
9
- label: string;
10
- value: string;
11
- }>;
12
8
  export declare function composeSupportingContext(bundle: ScanPresentationBundle): string[] | undefined;
13
9
  export declare function evidenceContextFromProfile(bundle: ScanPresentationBundle): {
14
10
  priority: "pr_intelligence" | "limited";
@@ -1 +1 @@
1
- {"version":3,"file":"narrativeCompose.d.ts","sourceRoot":"","sources":["../../../src/presentation/compose/narrativeCompose.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,4CAA4C,CAAC;AAMzF,OAAO,EACL,sBAAsB,EACtB,uBAAuB,GACxB,MAAM,wBAAwB,CAAC;AAShC,wBAAgB,eAAe,CAAC,MAAM,EAAE,sBAAsB,GAAG,MAAM,CAEtE;AAED,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,sBAAsB,GAC7B,MAAM,GAAG,SAAS,CAIpB;AAED,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,sBAAsB,EAC9B,GAAG,EAAE,MAAM,GACV,MAAM,EAAE,CAEV;AAED,wBAAgB,0BAA0B,CACxC,MAAM,EAAE,sBAAsB,EAC9B,GAAG,EAAE,MAAM,GACV,MAAM,EAAE,CAEV;AAED,wBAAgB,yBAAyB,CACvC,MAAM,EAAE,sBAAsB,EAC9B,GAAG,EAAE,MAAM,GACV,MAAM,EAAE,CAQV;AAED,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,sBAAsB,EAC9B,GAAG,EAAE,MAAM,GACV,KAAK,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CAmBzC;AAED,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,sBAAsB,GAC7B,MAAM,EAAE,GAAG,SAAS,CAwBtB;AAED,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,sBAAsB,GAAG;IAC1E,QAAQ,EAAE,iBAAiB,GAAG,SAAS,CAAC;IACxC,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B,CAKA"}
1
+ {"version":3,"file":"narrativeCompose.d.ts","sourceRoot":"","sources":["../../../src/presentation/compose/narrativeCompose.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,4CAA4C,CAAC;AAMzF,OAAO,EACL,sBAAsB,EACtB,uBAAuB,GACxB,MAAM,wBAAwB,CAAC;AAShC,wBAAgB,eAAe,CAAC,MAAM,EAAE,sBAAsB,GAAG,MAAM,CAEtE;AAED,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,sBAAsB,GAC7B,MAAM,GAAG,SAAS,CAIpB;AAED,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,sBAAsB,EAC9B,GAAG,EAAE,MAAM,GACV,MAAM,EAAE,CAEV;AAED,wBAAgB,0BAA0B,CACxC,MAAM,EAAE,sBAAsB,EAC9B,GAAG,EAAE,MAAM,GACV,MAAM,EAAE,CAEV;AAED,wBAAgB,yBAAyB,CACvC,MAAM,EAAE,sBAAsB,EAC9B,GAAG,EAAE,MAAM,GACV,MAAM,EAAE,CAQV;AAED,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,sBAAsB,GAC7B,MAAM,EAAE,GAAG,SAAS,CAwBtB;AAED,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,sBAAsB,GAAG;IAC1E,QAAQ,EAAE,iBAAiB,GAAG,SAAS,CAAC;IACxC,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B,CAKA"}
@@ -1,5 +1,4 @@
1
1
  import { formatCardAreaLabels } from "../../formatCardAreaLabels.js";
2
- import { formatChangedPackagesShort, labelBlastRadiusLevel, labelReachabilityKind, labelRuntimeSurface, } from "../../narrativePresentation.js";
3
2
  import { scanSurfaceCopy } from "../../scanSurfaceCopy.js";
4
3
  import { buildNarrativeChannels, projectCompactKeyPoints, } from "./narrativeChannels.js";
5
4
  export { buildNarrativeChannels, projectCompactKeyPoints, } from "./narrativeChannels.js";
@@ -36,25 +35,6 @@ export function composeAffectedAreaLabels(bundle, max) {
36
35
  }
37
36
  return labels;
38
37
  }
39
- export function composeEvidenceRows(bundle, max) {
40
- const { facts, profile } = bundle;
41
- const rows = [];
42
- if (!profile.interpretation.suppressRuntimeNarrative) {
43
- const runtime = labelRuntimeSurface(facts);
44
- if (runtime)
45
- rows.push({ label: "Runtime", value: runtime });
46
- const reach = labelReachabilityKind(facts);
47
- if (reach)
48
- rows.push({ label: "Reachability", value: reach });
49
- }
50
- const blast = labelBlastRadiusLevel(facts);
51
- if (blast)
52
- rows.push({ label: "Blast radius", value: blast });
53
- const changed = formatChangedPackagesShort(facts, 3);
54
- if (changed)
55
- rows.push({ label: "Changed", value: changed });
56
- return rows.slice(0, max);
57
- }
58
38
  export function composeSupportingContext(bundle) {
59
39
  const { facts, profile, result } = bundle;
60
40
  if (profile.density === "minimal")
@@ -10,5 +10,9 @@ export type AssessmentPresentationFields = {
10
10
  verificationChannel: VerificationChannel;
11
11
  reachVisibility: ReachVisibility;
12
12
  narrativeIntensity: NarrativeIntensity;
13
+ /** ABI 3 expression — optional confidence explanation. */
14
+ confidenceRationale?: string;
15
+ /** ABI 3 expression — optional focal-election narrative. */
16
+ electionSummary?: string;
13
17
  };
14
18
  //# sourceMappingURL=assessmentPresentationFields.d.ts.map
@@ -1 +1 @@
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;AAChC,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,+BAA+B,CAAC;AAEzE,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,mBAAmB,EAAE,mBAAmB,CAAC;IACzC,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;AAChC,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,+BAA+B,CAAC;AAEzE,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,mBAAmB,EAAE,mBAAmB,CAAC;IACzC,eAAe,EAAE,eAAe,CAAC;IACjC,kBAAkB,EAAE,kBAAkB,CAAC;IACvC,0DAA0D;IAC1D,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,4DAA4D;IAC5D,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B,CAAC"}
@@ -24,5 +24,5 @@ export { renderGitHubCheckRunMarkdown } from "./render/renderGitHubCheckRunMarkd
24
24
  export { buildGitHubCheckRunOutput, resolveWebAppOrigin, type GitHubCheckRunConclusion, type GitHubCheckRunOutput, type BuildGitHubCheckRunOutputOptions, } from "./buildGitHubCheckRunOutput.js";
25
25
  export { renderGitHubPrCommentMarkdown } from "./render/renderGitHubPrCommentMarkdown.js";
26
26
  export { renderCliScanSummaryText } from "./render/renderCliScanSummaryText.js";
27
- export { buildNarrativeChannels, projectCompactKeyPoints, composeHeadline, composeSubheadline, composeKeyPoints, composeVerificationActions, composeAffectedAreaLabels, composeEvidenceRows, composeSupportingContext, evidenceContextFromProfile, } from "./compose/narrativeCompose.js";
27
+ export { buildNarrativeChannels, projectCompactKeyPoints, composeHeadline, composeSubheadline, composeKeyPoints, composeVerificationActions, composeAffectedAreaLabels, composeSupportingContext, evidenceContextFromProfile, } from "./compose/narrativeCompose.js";
28
28
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/presentation/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,sBAAsB,EAAE,MAAM,2CAA2C,CAAC;AACxF,OAAO,EAAE,2BAA2B,EAAE,MAAM,gDAAgD,CAAC;AAC7F,YAAY,EAAE,gCAAgC,EAAE,MAAM,gDAAgD,CAAC;AACvG,OAAO,EAAE,yBAAyB,EAAE,MAAM,8CAA8C,CAAC;AACzF,YAAY,EAAE,8BAA8B,EAAE,MAAM,8CAA8C,CAAC;AACnG,OAAO,EAAE,4BAA4B,EAAE,MAAM,iDAAiD,CAAC;AAC/F,YAAY,EAAE,iCAAiC,EAAE,MAAM,iDAAiD,CAAC;AAEzG,YAAY,EAAE,mBAAmB,EAAE,MAAM,kCAAkC,CAAC;AAC5E,YAAY,EACV,kBAAkB,EAClB,0BAA0B,GAC3B,MAAM,gCAAgC,CAAC;AACxC,YAAY,EACV,cAAc,EACd,kBAAkB,EAClB,mBAAmB,EACnB,sBAAsB,EACtB,oBAAoB,EACpB,2BAA2B,EAC3B,uBAAuB,GACxB,MAAM,gBAAgB,CAAC;AAExB,YAAY,EAAE,yBAAyB,EAAE,MAAM,oCAAoC,CAAC;AACpF,YAAY,EAAE,mBAAmB,EAAE,MAAM,oCAAoC,CAAC;AAC9E,gDAAgD;AAChD,YAAY,EAAE,yBAAyB,IAAI,oBAAoB,EAAE,MAAM,oCAAoC,CAAC;AAC5G,YAAY,EAAE,uBAAuB,EAAE,MAAM,kCAAkC,CAAC;AAChF,YAAY,EACV,0BAA0B,EAC1B,2BAA2B,EAC3B,mBAAmB,GACpB,MAAM,mCAAmC,CAAC;AAE3C,OAAO,EACL,oBAAoB,EACpB,4BAA4B,EAC5B,sCAAsC,GACvC,MAAM,sCAAsC,CAAC;AAC9C,OAAO,EAAE,kBAAkB,EAAE,MAAM,oCAAoC,CAAC;AACxE,YAAY,EAAE,yBAAyB,EAAE,MAAM,oCAAoC,CAAC;AACpF,OAAO,EAAE,qBAAqB,EAAE,MAAM,uCAAuC,CAAC;AAC9E,OAAO,EAAE,sBAAsB,EAAE,MAAM,wCAAwC,CAAC;AAChF,OAAO,EAAE,qBAAqB,EAAE,MAAM,uCAAuC,CAAC;AAE9E,OAAO,EAAE,4BAA4B,EAAE,MAAM,0CAA0C,CAAC;AACxF,OAAO,EACL,yBAAyB,EACzB,mBAAmB,EACnB,KAAK,wBAAwB,EAC7B,KAAK,oBAAoB,EACzB,KAAK,gCAAgC,GACtC,MAAM,gCAAgC,CAAC;AACxC,OAAO,EAAE,6BAA6B,EAAE,MAAM,2CAA2C,CAAC;AAC1F,OAAO,EAAE,wBAAwB,EAAE,MAAM,sCAAsC,CAAC;AAEhF,OAAO,EACL,sBAAsB,EACtB,uBAAuB,EACvB,eAAe,EACf,kBAAkB,EAClB,gBAAgB,EAChB,0BAA0B,EAC1B,yBAAyB,EACzB,mBAAmB,EACnB,wBAAwB,EACxB,0BAA0B,GAC3B,MAAM,+BAA+B,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/presentation/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,sBAAsB,EAAE,MAAM,2CAA2C,CAAC;AACxF,OAAO,EAAE,2BAA2B,EAAE,MAAM,gDAAgD,CAAC;AAC7F,YAAY,EAAE,gCAAgC,EAAE,MAAM,gDAAgD,CAAC;AACvG,OAAO,EAAE,yBAAyB,EAAE,MAAM,8CAA8C,CAAC;AACzF,YAAY,EAAE,8BAA8B,EAAE,MAAM,8CAA8C,CAAC;AACnG,OAAO,EAAE,4BAA4B,EAAE,MAAM,iDAAiD,CAAC;AAC/F,YAAY,EAAE,iCAAiC,EAAE,MAAM,iDAAiD,CAAC;AAEzG,YAAY,EAAE,mBAAmB,EAAE,MAAM,kCAAkC,CAAC;AAC5E,YAAY,EACV,kBAAkB,EAClB,0BAA0B,GAC3B,MAAM,gCAAgC,CAAC;AACxC,YAAY,EACV,cAAc,EACd,kBAAkB,EAClB,mBAAmB,EACnB,sBAAsB,EACtB,oBAAoB,EACpB,2BAA2B,EAC3B,uBAAuB,GACxB,MAAM,gBAAgB,CAAC;AAExB,YAAY,EAAE,yBAAyB,EAAE,MAAM,oCAAoC,CAAC;AACpF,YAAY,EAAE,mBAAmB,EAAE,MAAM,oCAAoC,CAAC;AAC9E,gDAAgD;AAChD,YAAY,EAAE,yBAAyB,IAAI,oBAAoB,EAAE,MAAM,oCAAoC,CAAC;AAC5G,YAAY,EAAE,uBAAuB,EAAE,MAAM,kCAAkC,CAAC;AAChF,YAAY,EACV,0BAA0B,EAC1B,2BAA2B,EAC3B,mBAAmB,GACpB,MAAM,mCAAmC,CAAC;AAE3C,OAAO,EACL,oBAAoB,EACpB,4BAA4B,EAC5B,sCAAsC,GACvC,MAAM,sCAAsC,CAAC;AAC9C,OAAO,EAAE,kBAAkB,EAAE,MAAM,oCAAoC,CAAC;AACxE,YAAY,EAAE,yBAAyB,EAAE,MAAM,oCAAoC,CAAC;AACpF,OAAO,EAAE,qBAAqB,EAAE,MAAM,uCAAuC,CAAC;AAC9E,OAAO,EAAE,sBAAsB,EAAE,MAAM,wCAAwC,CAAC;AAChF,OAAO,EAAE,qBAAqB,EAAE,MAAM,uCAAuC,CAAC;AAE9E,OAAO,EAAE,4BAA4B,EAAE,MAAM,0CAA0C,CAAC;AACxF,OAAO,EACL,yBAAyB,EACzB,mBAAmB,EACnB,KAAK,wBAAwB,EAC7B,KAAK,oBAAoB,EACzB,KAAK,gCAAgC,GACtC,MAAM,gCAAgC,CAAC;AACxC,OAAO,EAAE,6BAA6B,EAAE,MAAM,2CAA2C,CAAC;AAC1F,OAAO,EAAE,wBAAwB,EAAE,MAAM,sCAAsC,CAAC;AAEhF,OAAO,EACL,sBAAsB,EACtB,uBAAuB,EACvB,eAAe,EACf,kBAAkB,EAClB,gBAAgB,EAChB,0BAA0B,EAC1B,yBAAyB,EACzB,wBAAwB,EACxB,0BAA0B,GAC3B,MAAM,+BAA+B,CAAC"}
@@ -10,4 +10,4 @@ export { renderGitHubCheckRunMarkdown } from "./render/renderGitHubCheckRunMarkd
10
10
  export { buildGitHubCheckRunOutput, resolveWebAppOrigin, } from "./buildGitHubCheckRunOutput.js";
11
11
  export { renderGitHubPrCommentMarkdown } from "./render/renderGitHubPrCommentMarkdown.js";
12
12
  export { renderCliScanSummaryText } from "./render/renderCliScanSummaryText.js";
13
- export { buildNarrativeChannels, projectCompactKeyPoints, composeHeadline, composeSubheadline, composeKeyPoints, composeVerificationActions, composeAffectedAreaLabels, composeEvidenceRows, composeSupportingContext, evidenceContextFromProfile, } from "./compose/narrativeCompose.js";
13
+ export { buildNarrativeChannels, projectCompactKeyPoints, composeHeadline, composeSubheadline, composeKeyPoints, composeVerificationActions, composeAffectedAreaLabels, composeSupportingContext, evidenceContextFromProfile, } from "./compose/narrativeCompose.js";
@@ -9,6 +9,7 @@ export type BuildScanPresentationBundleInput = {
9
9
  /**
10
10
  * Mandatory orchestration entrypoint for completed-scan presentation.
11
11
  * Assessment is the sole authority; profile is a thin projection.
12
+ * Consumes only the public ScanResult contract — see docs/engineering/presentation-ownership.md.
12
13
  */
13
14
  export declare function buildScanPresentationBundle(input: BuildScanPresentationBundleInput): ScanPresentationBundle | null;
14
15
  //# sourceMappingURL=buildScanPresentationBundle.d.ts.map
@@ -1 +1 @@
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;CAC1B,CAAC;AAEF;;;GAGG;AACH,wBAAgB,2BAA2B,CACzC,KAAK,EAAE,gCAAgC,GACtC,sBAAsB,GAAG,IAAI,CA4B/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;CAC1B,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,2BAA2B,CACzC,KAAK,EAAE,gCAAgC,GACtC,sBAAsB,GAAG,IAAI,CA4B/B"}
@@ -5,6 +5,7 @@ import { buildProfileFromAssessment } from "../profile/buildProfileFromAssessmen
5
5
  /**
6
6
  * Mandatory orchestration entrypoint for completed-scan presentation.
7
7
  * Assessment is the sole authority; profile is a thin projection.
8
+ * Consumes only the public ScanResult contract — see docs/engineering/presentation-ownership.md.
8
9
  */
9
10
  export function buildScanPresentationBundle(input) {
10
11
  if (input.pipelineStatus !== "done" || !input.result)
@@ -1 +1 @@
1
- {"version":3,"file":"presentCliScanSummary.d.ts","sourceRoot":"","sources":["../../../src/presentation/presenters/presentCliScanSummary.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,oCAAoC,CAAC;AAC9E,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,4CAA4C,CAAC;AAGzF,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,sBAAsB,EAC9B,GAAG,GAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAA;CAAO,GAC/B,mBAAmB,CAiCrB"}
1
+ {"version":3,"file":"presentCliScanSummary.d.ts","sourceRoot":"","sources":["../../../src/presentation/presenters/presentCliScanSummary.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,oCAAoC,CAAC;AAC9E,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,4CAA4C,CAAC;AAGzF,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,sBAAsB,EAC9B,GAAG,GAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAA;CAAO,GAC/B,mBAAmB,CAmCrB"}
@@ -1,14 +1,16 @@
1
- import { scoreToBandLabel } from "../../prRiskBand.js";
1
+ import { formatPrRiskSummary } from "../../prRiskBand.js";
2
2
  import { resolvePrRiskLayerScores } from "../../prRiskWire.js";
3
- import { buildNarrativeChannels, composeHeadline, composeSubheadline, composeSupportingContext, composeVerificationActions, evidenceContextFromProfile, projectCompactKeyPoints, } from "../compose/narrativeCompose.js";
3
+ import { buildNarrativeChannels, composeSubheadline, composeSupportingContext, evidenceContextFromProfile, projectCompactKeyPoints, } from "../compose/narrativeCompose.js";
4
4
  import { projectAssessmentFields } from "../projectAssessmentFields.js";
5
5
  export function presentCliScanSummary(bundle, ctx = {}) {
6
6
  const { facts, profile, result } = bundle;
7
+ const channels = buildNarrativeChannels(bundle);
7
8
  const layerScores = resolvePrRiskLayerScores(result);
8
9
  const layerLine = layerScores
9
10
  ? `security=${layerScores.security} maintainability=${layerScores.maintainability} ecosystem=${layerScores.ecosystem} upgradeImpact=${layerScores.upgradeImpact}`
10
11
  : "";
11
- const prRiskScore = facts.riskSignals?.riskIndex ?? facts.riskIndex ?? 0;
12
+ const prRisk = formatPrRiskSummary(facts);
13
+ const prRiskScore = prRisk?.prRiskScore ?? facts.riskIndex ?? 0;
12
14
  return {
13
15
  ...projectAssessmentFields(bundle),
14
16
  header: {
@@ -20,13 +22,13 @@ export function presentCliScanSummary(bundle, ctx = {}) {
20
22
  density: profile.density,
21
23
  confidence: profile.confidence,
22
24
  evidenceContext: evidenceContextFromProfile(bundle),
23
- headline: composeHeadline(bundle),
25
+ headline: channels.headline,
24
26
  subheadline: composeSubheadline(bundle),
25
- keyPoints: projectCompactKeyPoints(buildNarrativeChannels(bundle), 6),
26
- verificationActions: composeVerificationActions(bundle, 5),
27
+ keyPoints: projectCompactKeyPoints(channels, 6),
28
+ verificationActions: channels.verification.slice(0, 5),
27
29
  metrics: {
28
30
  prRiskScore,
29
- prRiskBandLabel: scoreToBandLabel(prRiskScore) ?? undefined,
31
+ prRiskBandLabel: prRisk?.prRiskBandLabel ?? undefined,
30
32
  riskIndex: prRiskScore,
31
33
  layerLine,
32
34
  findingCount: result.findings?.length ?? 0,
@@ -1 +1 @@
1
- {"version":3,"file":"presentGitHubCheckRun.d.ts","sourceRoot":"","sources":["../../../src/presentation/presenters/presentGitHubCheckRun.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,oCAAoC,CAAC;AACrF,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,4CAA4C,CAAC;AAGzF,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,sBAAsB,EAC9B,GAAG,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,OAAO,CAAA;CAAE,GAChE,0BAA0B,CA4C5B"}
1
+ {"version":3,"file":"presentGitHubCheckRun.d.ts","sourceRoot":"","sources":["../../../src/presentation/presenters/presentGitHubCheckRun.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,oCAAoC,CAAC;AACrF,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,4CAA4C,CAAC;AAGzF,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,sBAAsB,EAC9B,GAAG,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,OAAO,CAAA;CAAE,GAChE,0BAA0B,CAkD5B"}