@mergesignal/shared 0.4.3 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (171) hide show
  1. package/dist/actionsStepSummary.d.ts +1 -22
  2. package/dist/actionsStepSummary.d.ts.map +1 -1
  3. package/dist/actionsStepSummary.js +19 -716
  4. package/dist/actionsStepSummary.test.js +34 -329
  5. package/dist/assessmentLabels.d.ts +6 -0
  6. package/dist/assessmentLabels.d.ts.map +1 -0
  7. package/dist/assessmentLabels.js +33 -0
  8. package/dist/assessmentProjection.d.ts +12 -0
  9. package/dist/assessmentProjection.d.ts.map +1 -0
  10. package/dist/assessmentProjection.js +100 -0
  11. package/dist/assessmentSchema.d.ts +155 -0
  12. package/dist/assessmentSchema.d.ts.map +1 -0
  13. package/dist/assessmentSchema.js +110 -0
  14. package/dist/cardObservationCatalog.d.ts +2 -0
  15. package/dist/cardObservationCatalog.d.ts.map +1 -1
  16. package/dist/cardObservationCatalog.js +47 -1
  17. package/dist/engineWireRegression.test.js +22 -2
  18. package/dist/fixtures/assessmentFixtures.d.ts +13 -0
  19. package/dist/fixtures/assessmentFixtures.d.ts.map +1 -0
  20. package/dist/fixtures/assessmentFixtures.js +164 -0
  21. package/dist/formatCardExposureDisplay.d.ts +0 -4
  22. package/dist/formatCardExposureDisplay.d.ts.map +1 -1
  23. package/dist/formatCardExposureDisplay.js +0 -15
  24. package/dist/formatInsight.d.ts +3 -2
  25. package/dist/formatInsight.d.ts.map +1 -1
  26. package/dist/formatInsight.js +26 -1
  27. package/dist/index.d.ts +7 -11
  28. package/dist/index.d.ts.map +1 -1
  29. package/dist/index.js +7 -11
  30. package/dist/narrativeParity.test.js +4 -34
  31. package/dist/presentGitHubPrComment.d.ts +1 -3
  32. package/dist/presentGitHubPrComment.d.ts.map +1 -1
  33. package/dist/presentGitHubPrComment.js +0 -17
  34. package/dist/presentation/compose/narrativeChannels.d.ts.map +1 -1
  35. package/dist/presentation/compose/narrativeChannels.js +13 -43
  36. package/dist/presentation/compose/narrativeCompose.d.ts.map +1 -1
  37. package/dist/presentation/compose/narrativeCompose.js +2 -5
  38. package/dist/presentation/dto/assessmentPresentationFields.d.ts +13 -0
  39. package/dist/presentation/dto/assessmentPresentationFields.d.ts.map +1 -0
  40. package/dist/presentation/dto/assessmentPresentationFields.js +1 -0
  41. package/dist/presentation/dto/dashboardCardPresentation.d.ts +2 -1
  42. package/dist/presentation/dto/dashboardCardPresentation.d.ts.map +1 -1
  43. package/dist/presentation/dto/githubAndCliPresentation.d.ts +4 -3
  44. package/dist/presentation/dto/githubAndCliPresentation.d.ts.map +1 -1
  45. package/dist/presentation/dto/scanDetailsPresentation.d.ts +2 -1
  46. package/dist/presentation/dto/scanDetailsPresentation.d.ts.map +1 -1
  47. package/dist/presentation/fixtures/dashboardCardGolden.test.js +21 -14
  48. package/dist/presentation/fixtures/presentationPersonaFixtures.d.ts.map +1 -1
  49. package/dist/presentation/fixtures/presentationPersonaFixtures.js +31 -24
  50. package/dist/presentation/fixtures/scanResultFixtures.d.ts.map +1 -1
  51. package/dist/presentation/fixtures/scanResultFixtures.js +14 -3
  52. package/dist/presentation/index.d.ts +0 -1
  53. package/dist/presentation/index.d.ts.map +1 -1
  54. package/dist/presentation/index.js +0 -1
  55. package/dist/presentation/orchestration/buildScanCardPresentation.d.ts.map +1 -1
  56. package/dist/presentation/orchestration/buildScanCardPresentation.js +8 -3
  57. package/dist/presentation/orchestration/buildScanPresentationBundle.d.ts +1 -1
  58. package/dist/presentation/orchestration/buildScanPresentationBundle.d.ts.map +1 -1
  59. package/dist/presentation/orchestration/buildScanPresentationBundle.js +12 -10
  60. package/dist/presentation/orchestration/scanPresentationBundle.d.ts +8 -3
  61. package/dist/presentation/orchestration/scanPresentationBundle.d.ts.map +1 -1
  62. package/dist/presentation/presentationPersonas.test.js +6 -6
  63. package/dist/presentation/presenters/presentCliScanSummary.d.ts.map +1 -1
  64. package/dist/presentation/presenters/presentCliScanSummary.js +2 -0
  65. package/dist/presentation/presenters/presentDashboardCard.d.ts.map +1 -1
  66. package/dist/presentation/presenters/presentDashboardCard.js +2 -0
  67. package/dist/presentation/presenters/presentGitHubCheckRun.d.ts.map +1 -1
  68. package/dist/presentation/presenters/presentGitHubCheckRun.js +2 -0
  69. package/dist/presentation/presenters/presentGitHubPrComment.d.ts.map +1 -1
  70. package/dist/presentation/presenters/presentGitHubPrComment.js +15 -21
  71. package/dist/presentation/presenters/presentScanDetails.d.ts.map +1 -1
  72. package/dist/presentation/presenters/presentScanDetails.js +52 -129
  73. package/dist/presentation/profile/buildProfileFromAssessment.d.ts +5 -0
  74. package/dist/presentation/profile/buildProfileFromAssessment.d.ts.map +1 -0
  75. package/dist/presentation/profile/buildProfileFromAssessment.js +58 -0
  76. package/dist/presentation/projectAssessmentFields.d.ts +4 -0
  77. package/dist/presentation/projectAssessmentFields.d.ts.map +1 -0
  78. package/dist/presentation/projectAssessmentFields.js +13 -0
  79. package/dist/presentation/surfaceParity.test.d.ts +2 -0
  80. package/dist/presentation/surfaceParity.test.d.ts.map +1 -0
  81. package/dist/presentation/surfaceParity.test.js +74 -0
  82. package/dist/productMessaging.d.ts +4 -4
  83. package/dist/productMessaging.d.ts.map +1 -1
  84. package/dist/productMessaging.js +4 -4
  85. package/dist/productMessaging.test.js +2 -2
  86. package/dist/repoIntelligenceSchema.d.ts +2 -2
  87. package/dist/resolvePipelineStatus.d.ts +15 -0
  88. package/dist/resolvePipelineStatus.d.ts.map +1 -0
  89. package/dist/resolvePipelineStatus.js +37 -0
  90. package/dist/scanCardPresentationState.d.ts +4 -0
  91. package/dist/scanCardPresentationState.d.ts.map +1 -0
  92. package/dist/scanCardPresentationState.js +4 -0
  93. package/dist/{scanDetailViewModel.d.ts → scanDetailViewModelTypes.d.ts} +60 -32
  94. package/dist/scanDetailViewModelTypes.d.ts.map +1 -0
  95. package/dist/scanDetailViewModelTypes.js +4 -0
  96. package/dist/scanResultSchema.d.ts +75 -2
  97. package/dist/scanResultSchema.d.ts.map +1 -1
  98. package/dist/scanResultSchema.js +4 -2
  99. package/dist/scanResultSchema.test.js +16 -0
  100. package/dist/trustedScanGuards.test.js +7 -0
  101. package/dist/types.d.ts +3 -0
  102. package/dist/types.d.ts.map +1 -1
  103. package/package.json +1 -1
  104. package/dist/collectNarrativeWhyBullets.d.ts +0 -12
  105. package/dist/collectNarrativeWhyBullets.d.ts.map +0 -1
  106. package/dist/collectNarrativeWhyBullets.js +0 -104
  107. package/dist/deriveCardDisplaySummary.d.ts +0 -16
  108. package/dist/deriveCardDisplaySummary.d.ts.map +0 -1
  109. package/dist/deriveCardDisplaySummary.js +0 -56
  110. package/dist/deriveCardDisplaySummary.test.d.ts +0 -2
  111. package/dist/deriveCardDisplaySummary.test.d.ts.map +0 -1
  112. package/dist/deriveCardDisplaySummary.test.js +0 -89
  113. package/dist/deriveCardOperationalObservations.d.ts +0 -19
  114. package/dist/deriveCardOperationalObservations.d.ts.map +0 -1
  115. package/dist/deriveCardOperationalObservations.js +0 -180
  116. package/dist/deriveCardOperationalObservations.test.d.ts +0 -2
  117. package/dist/deriveCardOperationalObservations.test.d.ts.map +0 -1
  118. package/dist/deriveCardOperationalObservations.test.js +0 -268
  119. package/dist/deriveRiskScoreSummary.d.ts +0 -33
  120. package/dist/deriveRiskScoreSummary.d.ts.map +0 -1
  121. package/dist/deriveRiskScoreSummary.js +0 -90
  122. package/dist/deriveRiskScoreSummary.test.d.ts +0 -2
  123. package/dist/deriveRiskScoreSummary.test.d.ts.map +0 -1
  124. package/dist/deriveRiskScoreSummary.test.js +0 -47
  125. package/dist/deriveScanDetailRecommendations.d.ts +0 -63
  126. package/dist/deriveScanDetailRecommendations.d.ts.map +0 -1
  127. package/dist/deriveScanDetailRecommendations.js +0 -725
  128. package/dist/deriveScanDetailRecommendations.test.d.ts +0 -2
  129. package/dist/deriveScanDetailRecommendations.test.d.ts.map +0 -1
  130. package/dist/deriveScanDetailRecommendations.test.js +0 -181
  131. package/dist/deriveScanSummaryText.d.ts +0 -7
  132. package/dist/deriveScanSummaryText.d.ts.map +0 -1
  133. package/dist/deriveScanSummaryText.js +0 -24
  134. package/dist/deriveScanSummaryText.test.d.ts +0 -2
  135. package/dist/deriveScanSummaryText.test.d.ts.map +0 -1
  136. package/dist/deriveScanSummaryText.test.js +0 -77
  137. package/dist/formatCardEvidenceCounts.d.ts +0 -7
  138. package/dist/formatCardEvidenceCounts.d.ts.map +0 -1
  139. package/dist/formatCardEvidenceCounts.js +0 -19
  140. package/dist/prCheckRunPresentation.d.ts +0 -68
  141. package/dist/prCheckRunPresentation.d.ts.map +0 -1
  142. package/dist/prCheckRunPresentation.js +0 -319
  143. package/dist/prCheckRunPresentation.test.d.ts +0 -2
  144. package/dist/prCheckRunPresentation.test.d.ts.map +0 -1
  145. package/dist/prCheckRunPresentation.test.js +0 -278
  146. package/dist/presentation/intent/derivePresentationInterpretation.d.ts +0 -4
  147. package/dist/presentation/intent/derivePresentationInterpretation.d.ts.map +0 -1
  148. package/dist/presentation/intent/derivePresentationInterpretation.js +0 -202
  149. package/dist/presentation/intent/formatPresentationCopy.d.ts +0 -8
  150. package/dist/presentation/intent/formatPresentationCopy.d.ts.map +0 -1
  151. package/dist/presentation/intent/formatPresentationCopy.js +0 -140
  152. package/dist/presentation/intent/presentationIntent.test.d.ts +0 -2
  153. package/dist/presentation/intent/presentationIntent.test.d.ts.map +0 -1
  154. package/dist/presentation/intent/presentationIntent.test.js +0 -29
  155. package/dist/presentation/intent/verificationFocusLabels.d.ts +0 -2
  156. package/dist/presentation/intent/verificationFocusLabels.d.ts.map +0 -1
  157. package/dist/presentation/intent/verificationFocusLabels.js +0 -45
  158. package/dist/presentation/profile/derivePresentationProfile.d.ts +0 -12
  159. package/dist/presentation/profile/derivePresentationProfile.d.ts.map +0 -1
  160. package/dist/presentation/profile/derivePresentationProfile.js +0 -85
  161. package/dist/scanCardSummary.d.ts +0 -58
  162. package/dist/scanCardSummary.d.ts.map +0 -1
  163. package/dist/scanCardSummary.js +0 -146
  164. package/dist/scanCardSummary.test.d.ts +0 -2
  165. package/dist/scanCardSummary.test.d.ts.map +0 -1
  166. package/dist/scanCardSummary.test.js +0 -234
  167. package/dist/scanDetailViewModel.d.ts.map +0 -1
  168. package/dist/scanDetailViewModel.js +0 -636
  169. package/dist/scanDetailViewModel.test.d.ts +0 -2
  170. package/dist/scanDetailViewModel.test.d.ts.map +0 -1
  171. package/dist/scanDetailViewModel.test.js +0 -530
@@ -0,0 +1,58 @@
1
+ import { narrativeIntensityToDensity } from "../../assessmentSchema.js";
2
+ import { safeParseRepoIntelligence } from "../../repoIntelligenceSchema.js";
3
+ import { scanSurfaceCopy } from "../../scanSurfaceCopy.js";
4
+ import { collectVerificationFocus } from "../../assessmentProjection.js";
5
+ function buildInterpretation(assessment, presentation, result) {
6
+ const verificationLabels = collectVerificationFocus(result);
7
+ const anchorPackage = result.changedPackages?.[0] ?? null;
8
+ const suppressRuntimeNarrative = presentation.reachVisibility === "hidden";
9
+ let intent = "unknown_upgrade";
10
+ if (assessment.primaryConcern === "insufficient_evidence") {
11
+ intent = "limited_context";
12
+ }
13
+ else if (assessment.changeClasses.includes("tooling_maintenance")) {
14
+ intent = "tooling_patch";
15
+ }
16
+ else if (assessment.primaryConcern === "confirmed_runtime_usage") {
17
+ if (assessment.factors.includes("queue_infrastructure")) {
18
+ intent = "queue_runtime_upgrade";
19
+ }
20
+ else if (assessment.factors.includes("auth_infrastructure")) {
21
+ intent = "auth_runtime_upgrade";
22
+ }
23
+ else {
24
+ intent = "runtime_upgrade";
25
+ }
26
+ }
27
+ return {
28
+ intent,
29
+ anchorPackage,
30
+ suppressRuntimeNarrative,
31
+ allowRuntimeNarrative: !suppressRuntimeNarrative,
32
+ showLimitedEvidence: assessment.confidence === "low",
33
+ expectedImpactKey: null,
34
+ verificationLabels,
35
+ runtimeSurfaceLabel: null,
36
+ runtimePackages: [],
37
+ };
38
+ }
39
+ export function buildProfileFromAssessment(assessment, presentation, result) {
40
+ const riParse = safeParseRepoIntelligence(result.repoIntelligence);
41
+ const priority = riParse.ok && (result.changedPackages?.length ?? 0) > 0
42
+ ? "pr_intelligence"
43
+ : "limited";
44
+ const degradedMessage = assessment.primaryConcern === "insufficient_evidence" ||
45
+ assessment.confidence === "low"
46
+ ? scanSurfaceCopy.presentation.limitedContextMessage
47
+ : priority === "limited"
48
+ ? scanSurfaceCopy.presentation.limitedContextMessage
49
+ : undefined;
50
+ return {
51
+ status: assessment.posture,
52
+ density: narrativeIntensityToDensity(presentation.narrativeIntensity),
53
+ confidence: assessment.confidence,
54
+ priority,
55
+ degradedMessage,
56
+ interpretation: buildInterpretation(assessment, presentation, result),
57
+ };
58
+ }
@@ -0,0 +1,4 @@
1
+ import type { AssessmentPresentationFields } from "./dto/assessmentPresentationFields.js";
2
+ import type { ScanPresentationBundle } from "./orchestration/scanPresentationBundle.js";
3
+ export declare function projectAssessmentFields(bundle: ScanPresentationBundle): AssessmentPresentationFields;
4
+ //# sourceMappingURL=projectAssessmentFields.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"projectAssessmentFields.d.ts","sourceRoot":"","sources":["../../src/presentation/projectAssessmentFields.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,4BAA4B,EAAE,MAAM,uCAAuC,CAAC;AAC1F,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,2CAA2C,CAAC;AAExF,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,sBAAsB,GAC7B,4BAA4B,CAW9B"}
@@ -0,0 +1,13 @@
1
+ import { collectVerificationFocus, projectReasoningLines, } from "../assessmentProjection.js";
2
+ export function projectAssessmentFields(bundle) {
3
+ const { assessment, presentation, result } = bundle;
4
+ return {
5
+ posture: assessment.posture,
6
+ primaryConcern: assessment.primaryConcern,
7
+ factors: [...assessment.factors],
8
+ reasoning: projectReasoningLines(result),
9
+ verificationFocus: collectVerificationFocus(result),
10
+ reachVisibility: presentation.reachVisibility,
11
+ narrativeIntensity: presentation.narrativeIntensity,
12
+ };
13
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=surfaceParity.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"surfaceParity.test.d.ts","sourceRoot":"","sources":["../../src/presentation/surfaceParity.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,74 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { buildScanPresentationBundle } from "./orchestration/buildScanPresentationBundle.js";
3
+ import { presentDashboardCard } from "./presenters/presentDashboardCard.js";
4
+ import { presentScanDetails } from "./presenters/presentScanDetails.js";
5
+ import { presentGitHubCheckRun } from "./presenters/presentGitHubCheckRun.js";
6
+ import { presentGitHubPrComment } from "./presenters/presentGitHubPrComment.js";
7
+ import { renderGitHubCheckRunMarkdown } from "./render/renderGitHubCheckRunMarkdown.js";
8
+ import { renderGitHubPrCommentMarkdown } from "./render/renderGitHubPrCommentMarkdown.js";
9
+ import { scanResultBullmq, scanResultEslint, scanResultFastifyRuntime, scanResultMixedTypescriptFastify, scanResultPrettier, scanResultTypescriptPatch, scanResultVitest, } from "./fixtures/presentationPersonaFixtures.js";
10
+ import { projectAssessmentFields } from "./projectAssessmentFields.js";
11
+ const SCAN_ID = "22222222-2222-4222-8222-222222222222";
12
+ const ORIGIN = "https://app.example.com";
13
+ const validationPersonas = [
14
+ { name: "PR #26 mixed", result: scanResultMixedTypescriptFastify },
15
+ { name: "PR #27 fastify", result: scanResultFastifyRuntime },
16
+ { name: "PR #28 typescript", result: scanResultTypescriptPatch },
17
+ { name: "PR #29 prettier", result: scanResultPrettier },
18
+ { name: "PR #30 bullmq", result: scanResultBullmq },
19
+ { name: "eslint", result: scanResultEslint },
20
+ { name: "vitest", result: scanResultVitest },
21
+ ];
22
+ function surfacesFor(result) {
23
+ const bundle = buildScanPresentationBundle({
24
+ result,
25
+ pipelineStatus: "done",
26
+ });
27
+ const fields = projectAssessmentFields(bundle);
28
+ const card = presentDashboardCard(bundle);
29
+ const details = presentScanDetails(bundle, { scanId: SCAN_ID });
30
+ const check = presentGitHubCheckRun(bundle, {
31
+ scanId: SCAN_ID,
32
+ webAppOrigin: ORIGIN,
33
+ });
34
+ const comment = presentGitHubPrComment(bundle);
35
+ const checkMd = renderGitHubCheckRunMarkdown(check);
36
+ const commentMd = renderGitHubPrCommentMarkdown(comment);
37
+ return { bundle, fields, card, details, check, comment, checkMd, commentMd };
38
+ }
39
+ describe("surfaceParity guardrail", () => {
40
+ for (const persona of validationPersonas) {
41
+ it(`${persona.name}: posture and assessment fields match across surfaces`, () => {
42
+ const s = surfacesFor(persona.result);
43
+ expect(s.card.posture).toBe(s.fields.posture);
44
+ expect(s.details.posture).toBe(s.fields.posture);
45
+ expect(s.check.posture).toBe(s.fields.posture);
46
+ expect(s.comment.posture).toBe(s.fields.posture);
47
+ expect(s.card.verdict?.posture).toBe(s.fields.posture);
48
+ expect(s.card.primaryConcern).toBe(s.fields.primaryConcern);
49
+ expect(s.details.primaryConcern).toBe(s.fields.primaryConcern);
50
+ expect(s.check.primaryConcern).toBe(s.fields.primaryConcern);
51
+ expect(s.comment.primaryConcern).toBe(s.fields.primaryConcern);
52
+ expect(s.card.narrativeIntensity).toBe(s.fields.narrativeIntensity);
53
+ expect(s.details.narrativeIntensity).toBe(s.fields.narrativeIntensity);
54
+ expect(s.check.narrativeIntensity).toBe(s.fields.narrativeIntensity);
55
+ expect(s.comment.narrativeIntensity).toBe(s.fields.narrativeIntensity);
56
+ expect(s.card.reachVisibility).toBe(s.fields.reachVisibility);
57
+ expect(s.details.reachVisibility).toBe(s.fields.reachVisibility);
58
+ expect(s.check.reachVisibility).toBe(s.fields.reachVisibility);
59
+ expect(s.comment.reachVisibility).toBe(s.fields.reachVisibility);
60
+ expect(s.card.reasoning).toEqual(s.fields.reasoning);
61
+ expect(s.details.reasoning).toEqual(s.fields.reasoning);
62
+ expect(s.check.reasoning).toEqual(s.fields.reasoning);
63
+ expect(s.comment.reasoning).toEqual(s.fields.reasoning);
64
+ expect(s.card.verificationFocus).toEqual(s.fields.verificationFocus);
65
+ expect(s.details.verificationFocus).toEqual(s.fields.verificationFocus);
66
+ expect(s.check.verificationFocus).toEqual(s.fields.verificationFocus);
67
+ expect(s.comment.verificationFocus).toEqual(s.fields.verificationFocus);
68
+ });
69
+ it(`${persona.name}: headline matches across card and details`, () => {
70
+ const s = surfacesFor(persona.result);
71
+ expect(s.details.hero.headline).toBe(s.card.headline);
72
+ });
73
+ }
74
+ });
@@ -2,7 +2,7 @@
2
2
  * Canonical marketing / category copy. Operational scan strings stay in scanSurfaceCopy.
3
3
  */
4
4
  export declare const productMessaging: {
5
- readonly formalDefinition: "MergeSignal analyzes dependency upgrades, identifies affected application flows, and provides reviewer guidance before merge.";
5
+ readonly formalDefinition: "MergeSignal analyzes dependency upgrades in context, inspects relevant code paths, and provides focused reviewer guidance before merge - without requiring a full repository scan.";
6
6
  readonly hero: {
7
7
  readonly kicker: "Merge-decision intelligence for dependency upgrades";
8
8
  readonly h1: "See what a dependency upgrade can break.";
@@ -68,10 +68,10 @@ export declare const productMessaging: {
68
68
  readonly dashboardPrCard: {
69
69
  readonly intro: "The repository dashboard is a runtime-aware review surface for open upgrade pull requests: triage by merge recommendation, then read operational context on each card.";
70
70
  readonly posture: `Posture indicates the merge recommendation (${string}, ${string}, ${string}).`;
71
- readonly exposure: "Exposure indicates how broadly the upgrade touches runtime-relevant application areas.";
72
- readonly exposureCategoriesLead: "On each scanned card, exposure reads as one of:";
71
+ readonly exposure: "Reach indicates how prominently affected application paths are surfaced for this upgrade.";
72
+ readonly exposureCategoriesLead: "Risk index bands (supporting context) read as one of:";
73
73
  readonly exposureCategories: readonly string[];
74
- readonly cardBody: "Below the verdict, scanned cards lead with the changed package, runtime surface, reachability, blast radius, and affected areas when code intelligence is available; repository-wide graph signals appear only as supporting context.";
74
+ readonly cardBody: "Below the verdict, scanned cards lead with the changed package, affected areas, verification checks, and blast radius when code intelligence is available - focused on this PR, not the whole repository.";
75
75
  };
76
76
  };
77
77
  /** Illustrative scan-card example for homepage proof band and getting-started. */
@@ -1 +1 @@
1
- {"version":3,"file":"productMessaging.d.ts","sourceRoot":"","sources":["../src/productMessaging.ts"],"names":[],"mappings":"AAGA;;GAEG;AAEH,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAmF3B,6FAA6F;;;;;;;;;CAYrF,CAAC;AAEX,kFAAkF;AAClF,eAAO,MAAM,gBAAgB;;;;CAOnB,CAAC;AAEX,iEAAiE;AACjE,wBAAgB,wBAAwB,IAAI,MAAM,EAAE,CAOnD"}
1
+ {"version":3,"file":"productMessaging.d.ts","sourceRoot":"","sources":["../src/productMessaging.ts"],"names":[],"mappings":"AAGA;;GAEG;AAEH,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAmF3B,6FAA6F;;;;;;;;;CAarF,CAAC;AAEX,kFAAkF;AAClF,eAAO,MAAM,gBAAgB;;;;CAOnB,CAAC;AAEX,iEAAiE;AACjE,wBAAgB,wBAAwB,IAAI,MAAM,EAAE,CAOnD"}
@@ -4,7 +4,7 @@ import { MERGE_POSTURE_LABEL } from "./riskVocabulary.js";
4
4
  * Canonical marketing / category copy. Operational scan strings stay in scanSurfaceCopy.
5
5
  */
6
6
  export const productMessaging = {
7
- formalDefinition: "MergeSignal analyzes dependency upgrades, identifies affected application flows, and provides reviewer guidance before merge.",
7
+ formalDefinition: "MergeSignal analyzes dependency upgrades in context, inspects relevant code paths, and provides focused reviewer guidance before merge - without requiring a full repository scan.",
8
8
  hero: {
9
9
  kicker: "Merge-decision intelligence for dependency upgrades",
10
10
  h1: "See what a dependency upgrade can break.",
@@ -83,10 +83,10 @@ export const productMessaging = {
83
83
  dashboardPrCard: {
84
84
  intro: "The repository dashboard is a runtime-aware review surface for open upgrade pull requests: triage by merge recommendation, then read operational context on each card.",
85
85
  posture: `Posture indicates the merge recommendation (${MERGE_POSTURE_LABEL.safe}, ${MERGE_POSTURE_LABEL.needs_review}, ${MERGE_POSTURE_LABEL.risky}).`,
86
- exposure: "Exposure indicates how broadly the upgrade touches runtime-relevant application areas.",
87
- exposureCategoriesLead: "On each scanned card, exposure reads as one of:",
86
+ exposure: "Reach indicates how prominently affected application paths are surfaced for this upgrade.",
87
+ exposureCategoriesLead: "Risk index bands (supporting context) read as one of:",
88
88
  exposureCategories: CARD_EXPOSURE_CATEGORY_LABELS,
89
- cardBody: "Below the verdict, scanned cards lead with the changed package, runtime surface, reachability, blast radius, and affected areas when code intelligence is available; repository-wide graph signals appear only as supporting context.",
89
+ cardBody: "Below the verdict, scanned cards lead with the changed package, affected areas, verification checks, and blast radius when code intelligence is available - focused on this PR, not the whole repository.",
90
90
  },
91
91
  };
92
92
  /** Illustrative scan-card example for homepage proof band and getting-started. */
@@ -71,8 +71,8 @@ describe("productMessaging", () => {
71
71
  d.cardBody,
72
72
  ].join(" ");
73
73
  expect(text).toContain("merge recommendation");
74
- expect(text).toContain("runtime-relevant");
75
- expect(text).not.toMatch(/risk index|total score|0-100|formula|weight/i);
74
+ expect(text).toContain("affected application paths");
75
+ expect(text).not.toMatch(/total score|0-100|formula|weight/i);
76
76
  expect(d.exposureCategories).toHaveLength(5);
77
77
  expect(d.exposureCategories).toContain("Elevated exposure");
78
78
  });
@@ -35,13 +35,13 @@ export declare const repoIntelligenceWireSchema: z.ZodObject<{
35
35
  }, z.core.$strip>;
36
36
  areas: z.ZodOptional<z.ZodArray<z.ZodString>>;
37
37
  dependencyClass: z.ZodOptional<z.ZodEnum<{
38
+ format: "format";
38
39
  unknown: "unknown";
39
40
  runtime: "runtime";
40
41
  build: "build";
41
42
  test: "test";
42
43
  tooling: "tooling";
43
44
  lint: "lint";
44
- format: "format";
45
45
  ci: "ci";
46
46
  }>>;
47
47
  packageRole: z.ZodOptional<z.ZodEnum<{
@@ -64,9 +64,9 @@ export declare const repoIntelligenceWireSchema: z.ZodObject<{
64
64
  development: "development";
65
65
  }>>;
66
66
  runtimeImpact: z.ZodOptional<z.ZodEnum<{
67
+ none: "none";
67
68
  unknown: "unknown";
68
69
  confirmed: "confirmed";
69
- none: "none";
70
70
  possible: "possible";
71
71
  }>>;
72
72
  expectedImpact: z.ZodOptional<z.ZodEnum<{
@@ -0,0 +1,15 @@
1
+ export type ScanPipelineStatus = "queued" | "running" | "done" | "failed";
2
+ export type PipelineCompletionEvidence = {
3
+ scannedAt?: string | null;
4
+ decision?: string | null;
5
+ totalScore?: number | null;
6
+ hasResult?: boolean;
7
+ };
8
+ /** Scan completion signals — decision/totalScore/result are only set after analysis. */
9
+ export declare function hasScanCompletionEvidence(evidence: PipelineCompletionEvidence): boolean;
10
+ /**
11
+ * Resolve wire status using completion evidence (decision, totalScore, result).
12
+ * Handles races where denormalized columns are written before status flips to done.
13
+ */
14
+ export declare function resolvePipelineStatus(status: string | undefined, evidence: PipelineCompletionEvidence): ScanPipelineStatus;
15
+ //# sourceMappingURL=resolvePipelineStatus.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolvePipelineStatus.d.ts","sourceRoot":"","sources":["../src/resolvePipelineStatus.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,kBAAkB,GAAG,QAAQ,GAAG,SAAS,GAAG,MAAM,GAAG,QAAQ,CAAC;AAE1E,MAAM,MAAM,0BAA0B,GAAG;IACvC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB,CAAC;AAsBF,wFAAwF;AACxF,wBAAgB,yBAAyB,CACvC,QAAQ,EAAE,0BAA0B,GACnC,OAAO,CAQT;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,MAAM,GAAG,SAAS,EAC1B,QAAQ,EAAE,0BAA0B,GACnC,kBAAkB,CAKpB"}
@@ -0,0 +1,37 @@
1
+ function normalizePipelineStatus(status) {
2
+ const st = String(status ?? "")
3
+ .trim()
4
+ .toLowerCase();
5
+ if (st === "queued" || st === "running" || st === "done" || st === "failed") {
6
+ return st;
7
+ }
8
+ return "failed";
9
+ }
10
+ function isMergePostureDecision(decision) {
11
+ return (decision === "safe" || decision === "needs_review" || decision === "risky");
12
+ }
13
+ /** Scan completion signals — decision/totalScore/result are only set after analysis. */
14
+ export function hasScanCompletionEvidence(evidence) {
15
+ if (isMergePostureDecision(evidence.decision))
16
+ return true;
17
+ if (evidence.hasResult === true)
18
+ return true;
19
+ if (evidence.totalScore != null && Number.isFinite(evidence.totalScore)) {
20
+ return true;
21
+ }
22
+ if (evidence.scannedAt?.trim())
23
+ return true;
24
+ return false;
25
+ }
26
+ /**
27
+ * Resolve wire status using completion evidence (decision, totalScore, result).
28
+ * Handles races where denormalized columns are written before status flips to done.
29
+ */
30
+ export function resolvePipelineStatus(status, evidence) {
31
+ const normalized = normalizePipelineStatus(status);
32
+ if (normalized === "done" || normalized === "failed")
33
+ return normalized;
34
+ if (hasScanCompletionEvidence(evidence))
35
+ return "done";
36
+ return normalized;
37
+ }
@@ -0,0 +1,4 @@
1
+ /** Dashboard PR card lifecycle — distinct from pipeline status. */
2
+ export type ScanCardPresentationState = "not_scanned" | "scanning" | "analysis_failed" | "ready" | "stale";
3
+ export declare function staleScanSubline(): string;
4
+ //# sourceMappingURL=scanCardPresentationState.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scanCardPresentationState.d.ts","sourceRoot":"","sources":["../src/scanCardPresentationState.ts"],"names":[],"mappings":"AAAA,mEAAmE;AACnE,MAAM,MAAM,yBAAyB,GACjC,aAAa,GACb,UAAU,GACV,iBAAiB,GACjB,OAAO,GACP,OAAO,CAAC;AAIZ,wBAAgB,gBAAgB,IAAI,MAAM,CAEzC"}
@@ -0,0 +1,4 @@
1
+ const STALE_SUBLINE = "Based on earlier commit";
2
+ export function staleScanSubline() {
3
+ return STALE_SUBLINE;
4
+ }
@@ -1,13 +1,63 @@
1
- import type { ScanNarrativeFacts } from "./scanNarrativeFacts.js";
2
- import { type ScanDetailRecommendationCenter } from "./deriveScanDetailRecommendations.js";
3
- import { type ScanDetailSignalSummary } from "./deriveRiskScoreSummary.js";
4
- import { type MergePosture } from "./riskVocabulary.js";
5
- import type { FindingSeverity, ScanResult } from "./types.js";
6
- export declare const ACT2_MAX_THEMES = 4;
7
- export declare const ACT2_MAX_THEME_CHARS = 80;
8
- export declare const VERDICT_LINE_MAX_CHARS = 120;
1
+ import type { ObservationSignalFamily } from "./cardObservationCatalog.js";
2
+ import type { NarrativeAvailabilityMode } from "./scanNarrativeFacts.js";
3
+ import type { MergePosture } from "./riskVocabulary.js";
4
+ import type { FindingSeverity, ScoreLayer } from "./types.js";
5
+ /** Max operational-impact rows before collapse on scan detail. */
9
6
  export declare const TIER1_MAX_VISIBLE_IMPACTS = 3;
7
+ /** Findings list collapse threshold on scan detail evidence panel. */
10
8
  export declare const ACT3_EVIDENCE_COLLAPSE_THRESHOLD = 10;
9
+ export type ScanDetailOverallRiskBand = "low" | "moderate" | "high";
10
+ export type ScanDetailLayerConcernLevel = "low" | "medium" | "high";
11
+ export type ScanDetailSignalLayer = {
12
+ layer: ScoreLayer;
13
+ label: string;
14
+ score: number;
15
+ concernLevel: ScanDetailLayerConcernLevel;
16
+ concernLabel: string;
17
+ };
18
+ export type RiskScoreGaugeModel = {
19
+ fillPercent: number;
20
+ band: ScanDetailOverallRiskBand;
21
+ ariaLabel: string;
22
+ };
23
+ export type ScanDetailSignalSummary = {
24
+ score: number;
25
+ overallBand: ScanDetailOverallRiskBand;
26
+ overallLabel: string;
27
+ gauge: RiskScoreGaugeModel;
28
+ layers: ScanDetailSignalLayer[];
29
+ };
30
+ export type RecommendationPriority = "high" | "medium" | "low";
31
+ export type GuidanceSource = "insight" | "recommendation" | "verification";
32
+ export type ScanDetailRecommendationDetail = {
33
+ why: string;
34
+ whyNow: string;
35
+ signals: string[];
36
+ affectedPackages?: {
37
+ names: string[];
38
+ overflowCount: number;
39
+ };
40
+ expectedBenefit: string;
41
+ };
42
+ export type ScanDetailRecommendation = {
43
+ id: string;
44
+ rank: number;
45
+ title: string;
46
+ priority: RecommendationPriority;
47
+ source: GuidanceSource;
48
+ signalFamily?: ObservationSignalFamily | null;
49
+ detail: ScanDetailRecommendationDetail;
50
+ proofRefs?: {
51
+ findingIds?: string[];
52
+ };
53
+ };
54
+ export type ScanDetailRecommendationCenter = {
55
+ heading: string;
56
+ defaultSelectedId: string;
57
+ items: ScanDetailRecommendation[];
58
+ posture: MergePosture | null;
59
+ scanContext?: string;
60
+ };
11
61
  export type ScanDetailOperationalImpactItem = {
12
62
  message: string;
13
63
  where?: string;
@@ -59,7 +109,7 @@ export type ScanDetailTopology = {
59
109
  }>;
60
110
  };
61
111
  export type ScanDetailNarrativeContext = {
62
- mode: import("./scanNarrativeFacts.js").NarrativeAvailabilityMode;
112
+ mode: NarrativeAvailabilityMode;
63
113
  codeIntelligenceAvailable: boolean;
64
114
  changedPackagesDisplay: string | null;
65
115
  runtimeSurfaceLabel: string | null;
@@ -106,26 +156,4 @@ export type ScanDetailViewModel = {
106
156
  codeIntelligenceAvailable?: boolean;
107
157
  };
108
158
  };
109
- export type DeriveScanDetailOptions = {
110
- scanId: string;
111
- status: "queued" | "running" | "done" | "failed";
112
- methodologyVersion?: string | null;
113
- prNumber?: number | null;
114
- repoContext?: ScanDetailViewModel["repoContext"];
115
- };
116
- /** Bridge copy from Signal summary to Recommended actions. */
117
- export declare function deriveFollowUpBridgeNote(actionCount: number): string | null;
118
- /** Act 2 theme sanitizer — strips package/CVE/version content. */
119
- export declare function sanitizeAct2Theme(raw: string): string | null;
120
- /** Verdict line from posture + reach band (scanSurfaceCopy.scanDetail.verdictLine). */
121
- export declare function deriveVerdictLine(posture: MergePosture | null, totalScore: number | null | undefined): string;
122
- export declare function deriveAct2Themes(result: ScanResult): string[];
123
- export declare function deriveOperationalImpact(result: ScanResult, verifyLabels?: Set<string>): ScanDetailOperationalImpact;
124
- export declare function presentScanDetailNarrativeContext(facts: ScanNarrativeFacts): ScanDetailNarrativeContext;
125
- export declare function deriveVerdictLineFromFacts(facts: ScanNarrativeFacts, result: ScanResult): string;
126
- /** Scan detail presentation from shared narrative facts. */
127
- export declare function presentScanDetailViewModel(facts: ScanNarrativeFacts, result: ScanResult, options: DeriveScanDetailOptions): ScanDetailViewModel;
128
- export declare function deriveScanDetailViewModel(result: ScanResult | null | undefined, options: DeriveScanDetailOptions): ScanDetailViewModel | null;
129
- /** Tier 1 recall test helper — true when message describes application-level impact. */
130
- export declare function tier1PassesRecallTest(operationalImpact: ScanDetailOperationalImpact): boolean;
131
- //# sourceMappingURL=scanDetailViewModel.d.ts.map
159
+ //# sourceMappingURL=scanDetailViewModelTypes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scanDetailViewModelTypes.d.ts","sourceRoot":"","sources":["../src/scanDetailViewModelTypes.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ /** Max operational-impact rows before collapse on scan detail. */
2
+ export const TIER1_MAX_VISIBLE_IMPACTS = 3;
3
+ /** Findings list collapse threshold on scan detail evidence panel. */
4
+ export const ACT3_EVIDENCE_COLLAPSE_THRESHOLD = 10;
@@ -1,9 +1,9 @@
1
1
  import { z } from "zod";
2
2
  import type { EngineEmittedScanResult, ScanResult } from "./types.js";
3
3
  /** Bump when persisted `result` JSON validation rules change materially (relaxed / legacy-tolerant). */
4
- export declare const SCAN_RESULT_ABI: "1";
4
+ export declare const SCAN_RESULT_ABI: "2";
5
5
  /** Bump when strict fresh-engine-output validation rules change materially. */
6
- export declare const ENGINE_OUTPUT_SCAN_ABI: "2";
6
+ export declare const ENGINE_OUTPUT_SCAN_ABI: "3";
7
7
  /**
8
8
  * Minimum structural invariants for **persisted** `scans.result` JSON and legacy reads.
9
9
  * `methodologyVersion` stays optional so historical rows without it remain valid.
@@ -88,6 +88,79 @@ export declare const engineOutputScanResultSchema: z.ZodObject<{
88
88
  codeAnalysisMetrics: z.ZodOptional<z.ZodUnknown>;
89
89
  methodologyVersion: z.ZodString;
90
90
  generatedAt: z.ZodString;
91
+ assessment: z.ZodObject<{
92
+ posture: z.ZodEnum<{
93
+ safe: "safe";
94
+ needs_review: "needs_review";
95
+ risky: "risky";
96
+ }>;
97
+ confidence: z.ZodEnum<{
98
+ low: "low";
99
+ medium: "medium";
100
+ high: "high";
101
+ }>;
102
+ primaryConcern: z.ZodNullable<z.ZodEnum<{
103
+ confirmed_runtime_usage: "confirmed_runtime_usage";
104
+ security_finding: "security_finding";
105
+ breaking_or_major: "breaking_or_major";
106
+ behavioral_change: "behavioral_change";
107
+ ecosystem_risk: "ecosystem_risk";
108
+ insufficient_evidence: "insufficient_evidence";
109
+ graph_baseline_only: "graph_baseline_only";
110
+ }>>;
111
+ concerns: z.ZodArray<z.ZodObject<{
112
+ kind: z.ZodEnum<{
113
+ confirmed_runtime_usage: "confirmed_runtime_usage";
114
+ security_finding: "security_finding";
115
+ breaking_or_major: "breaking_or_major";
116
+ behavioral_change: "behavioral_change";
117
+ ecosystem_risk: "ecosystem_risk";
118
+ insufficient_evidence: "insufficient_evidence";
119
+ graph_baseline_only: "graph_baseline_only";
120
+ }>;
121
+ rank: z.ZodNumber;
122
+ packages: z.ZodOptional<z.ZodArray<z.ZodString>>;
123
+ evidenceRefs: z.ZodArray<z.ZodString>;
124
+ }, z.core.$strip>>;
125
+ factors: z.ZodArray<z.ZodString>;
126
+ changeClasses: z.ZodArray<z.ZodEnum<{
127
+ tooling_maintenance: "tooling_maintenance";
128
+ test_infra: "test_infra";
129
+ runtime_patch: "runtime_patch";
130
+ runtime_upgrade: "runtime_upgrade";
131
+ security_advisory: "security_advisory";
132
+ breaking_change: "breaking_change";
133
+ ecosystem_unknown: "ecosystem_unknown";
134
+ bulk_mixed: "bulk_mixed";
135
+ removal: "removal";
136
+ }>>;
137
+ presentation: z.ZodObject<{
138
+ narrativeIntensity: z.ZodEnum<{
139
+ minimal: "minimal";
140
+ standard: "standard";
141
+ elevated: "elevated";
142
+ }>;
143
+ reachVisibility: z.ZodEnum<{
144
+ hidden: "hidden";
145
+ contextual: "contextual";
146
+ prominent: "prominent";
147
+ }>;
148
+ verificationIntensity: z.ZodEnum<{
149
+ none: "none";
150
+ advisory: "advisory";
151
+ required: "required";
152
+ }>;
153
+ insightEmissionFloor: z.ZodEnum<{
154
+ none: "none";
155
+ explain_only: "explain_only";
156
+ full: "full";
157
+ }>;
158
+ reportMode: z.ZodEnum<{
159
+ lightweight_pr_graph_baseline: "lightweight_pr_graph_baseline";
160
+ high_signal_pr: "high_signal_pr";
161
+ }>;
162
+ }, z.core.$strip>;
163
+ }, z.core.$strip>;
91
164
  }, z.core.$loose>;
92
165
  export type EngineOutputScanResultParseFailure = {
93
166
  ok: false;
@@ -1 +1 @@
1
- {"version":3,"file":"scanResultSchema.d.ts","sourceRoot":"","sources":["../src/scanResultSchema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,uBAAuB,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAEtE,wGAAwG;AACxG,eAAO,MAAM,eAAe,EAAG,GAAY,CAAC;AAE5C,+EAA+E;AAC/E,eAAO,MAAM,sBAAsB,EAAG,GAAY,CAAC;AASnD;;;;GAIG;AACH,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBA4Bb,CAAC;AAUjB;;;GAGG;AACH,eAAO,MAAM,4BAA4B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAGvC,CAAC;AAEH,MAAM,MAAM,kCAAkC,GAAG;IAC/C,EAAE,EAAE,KAAK,CAAC;IACV,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,kCAAkC,GAAG;IAC/C,EAAE,EAAE,IAAI,CAAC;IACT,MAAM,EAAE,uBAAuB,CAAC;CACjC,CAAC;AAEF,wBAAgB,+BAA+B,CAC7C,IAAI,EAAE,OAAO,GACZ,kCAAkC,GAAG,kCAAkC,CAazE;AAED,uFAAuF;AACvF,wBAAgB,kCAAkC,CAChD,IAAI,EAAE,OAAO,GACZ,uBAAuB,CAMzB;AAED,MAAM,MAAM,sBAAsB,GAAG;IACnC,EAAE,EAAE,KAAK,CAAC;IACV,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,sBAAsB,GAAG;IACnC,EAAE,EAAE,IAAI,CAAC;IACT,MAAM,EAAE,UAAU,CAAC;CACpB,CAAC;AAEF,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,OAAO,GACZ,sBAAsB,GAAG,sBAAsB,CAajD;AAED,yEAAyE;AACzE,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,OAAO,GAAG,UAAU,CAMhE"}
1
+ {"version":3,"file":"scanResultSchema.d.ts","sourceRoot":"","sources":["../src/scanResultSchema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,KAAK,EAAE,uBAAuB,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAEtE,wGAAwG;AACxG,eAAO,MAAM,eAAe,EAAG,GAAY,CAAC;AAE5C,+EAA+E;AAC/E,eAAO,MAAM,sBAAsB,EAAG,GAAY,CAAC;AASnD;;;;GAIG;AACH,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBA4Bb,CAAC;AAUjB;;;GAGG;AACH,eAAO,MAAM,4BAA4B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAIvC,CAAC;AAEH,MAAM,MAAM,kCAAkC,GAAG;IAC/C,EAAE,EAAE,KAAK,CAAC;IACV,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,kCAAkC,GAAG;IAC/C,EAAE,EAAE,IAAI,CAAC;IACT,MAAM,EAAE,uBAAuB,CAAC;CACjC,CAAC;AAEF,wBAAgB,+BAA+B,CAC7C,IAAI,EAAE,OAAO,GACZ,kCAAkC,GAAG,kCAAkC,CAazE;AAED,uFAAuF;AACvF,wBAAgB,kCAAkC,CAChD,IAAI,EAAE,OAAO,GACZ,uBAAuB,CAMzB;AAED,MAAM,MAAM,sBAAsB,GAAG;IACnC,EAAE,EAAE,KAAK,CAAC;IACV,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,sBAAsB,GAAG;IACnC,EAAE,EAAE,IAAI,CAAC;IACT,MAAM,EAAE,UAAU,CAAC;CACpB,CAAC;AAEF,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,OAAO,GACZ,sBAAsB,GAAG,sBAAsB,CAajD;AAED,yEAAyE;AACzE,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,OAAO,GAAG,UAAU,CAMhE"}
@@ -1,8 +1,9 @@
1
1
  import { z } from "zod";
2
+ import { assessmentSchema } from "./assessmentSchema.js";
2
3
  /** Bump when persisted `result` JSON validation rules change materially (relaxed / legacy-tolerant). */
3
- export const SCAN_RESULT_ABI = "1";
4
+ export const SCAN_RESULT_ABI = "2";
4
5
  /** Bump when strict fresh-engine-output validation rules change materially. */
5
- export const ENGINE_OUTPUT_SCAN_ABI = "2";
6
+ export const ENGINE_OUTPUT_SCAN_ABI = "3";
6
7
  const layerScoresSchema = z.object({
7
8
  security: z.number(),
8
9
  maintainability: z.number(),
@@ -57,6 +58,7 @@ const engineOutputGeneratedAtSchema = z
57
58
  export const engineOutputScanResultSchema = scanResultSchema.extend({
58
59
  methodologyVersion: z.string().trim().min(1),
59
60
  generatedAt: engineOutputGeneratedAtSchema,
61
+ assessment: assessmentSchema,
60
62
  });
61
63
  export function safeParseEngineOutputScanResult(data) {
62
64
  const parsed = engineOutputScanResultSchema.safeParse(data);
@@ -77,10 +77,26 @@ describe("scanResultSchema", () => {
77
77
  expect(parsed.findings).toEqual([]);
78
78
  });
79
79
  });
80
+ const minimalAssessment = {
81
+ posture: "safe",
82
+ confidence: "high",
83
+ primaryConcern: null,
84
+ concerns: [],
85
+ factors: ["tooling_maintenance"],
86
+ changeClasses: ["tooling_maintenance"],
87
+ presentation: {
88
+ narrativeIntensity: "minimal",
89
+ reachVisibility: "hidden",
90
+ verificationIntensity: "advisory",
91
+ insightEmissionFloor: "none",
92
+ reportMode: "high_signal_pr",
93
+ },
94
+ };
80
95
  describe("engineOutputScanResultSchema (strict, fresh engine only)", () => {
81
96
  const withMethodology = {
82
97
  ...minimalValid,
83
98
  methodologyVersion: "engine-test-fixture/v1",
99
+ assessment: minimalAssessment,
84
100
  };
85
101
  it("rejects payload that relaxed parser accepts when methodology is missing", () => {
86
102
  const r = safeParseEngineOutputScanResult(minimalValid);
@@ -1,5 +1,6 @@
1
1
  import { describe, it, expect, beforeEach, afterEach } from "vitest";
2
2
  import { assertTrustedActionsSummaryAllowed, assertTrustedScanResult, auditTrustedActionsOutput, isStubMethodologyVersion, trustedActionsSummaryDenylistPhrases, validateTrustedEngineScanResult, } from "./trustedScanGuards.js";
3
+ import { assessmentStub } from "./fixtures/assessmentFixtures.js";
3
4
  import { scanSurfaceCopy } from "./scanSurfaceCopy.js";
4
5
  const baseResult = {
5
6
  totalScore: 10,
@@ -13,6 +14,12 @@ const baseResult = {
13
14
  recommendations: [],
14
15
  generatedAt: "2026-01-01T00:00:00.000Z",
15
16
  methodologyVersion: "engine-stub/v2",
17
+ assessment: assessmentStub,
18
+ decision: {
19
+ recommendation: "needs_review",
20
+ confidence: "low",
21
+ reasoning: ["Stub engine cannot perform real analysis"],
22
+ },
16
23
  };
17
24
  describe("trustedScanGuards", () => {
18
25
  it("detects stub methodology", () => {