@mergesignal/shared 0.2.5 → 0.2.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/deriveScanNarrative.d.ts +10 -0
- package/dist/deriveScanNarrative.d.ts.map +1 -0
- package/dist/deriveScanNarrative.js +267 -0
- package/dist/deriveScanNarrative.test.d.ts +2 -0
- package/dist/deriveScanNarrative.test.d.ts.map +1 -0
- package/dist/deriveScanNarrative.test.js +109 -0
- package/dist/extractRepositoryContextFacts.d.ts +16 -0
- package/dist/extractRepositoryContextFacts.d.ts.map +1 -0
- package/dist/extractRepositoryContextFacts.js +71 -0
- package/dist/fixtures/repoIntelligenceFixtures.d.ts +8 -0
- package/dist/fixtures/repoIntelligenceFixtures.d.ts.map +1 -0
- package/dist/fixtures/repoIntelligenceFixtures.js +47 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -0
- package/dist/prCheckRunPresentation.js +1 -1
- package/dist/presentScanCardSummary.d.ts +16 -0
- package/dist/presentScanCardSummary.d.ts.map +1 -0
- package/dist/presentScanCardSummary.js +207 -0
- package/dist/productMessaging.d.ts +1 -1
- package/dist/productMessaging.js +1 -1
- package/dist/repoIntelligenceSchema.d.ts +123 -0
- package/dist/repoIntelligenceSchema.d.ts.map +1 -0
- package/dist/repoIntelligenceSchema.js +174 -0
- package/dist/scanCardSummary.d.ts +12 -2
- package/dist/scanCardSummary.d.ts.map +1 -1
- package/dist/scanCardSummary.js +16 -57
- package/dist/scanCardSummary.test.js +13 -0
- package/dist/scanDetailViewModel.d.ts +14 -0
- package/dist/scanDetailViewModel.d.ts.map +1 -1
- package/dist/scanDetailViewModel.js +119 -30
- package/dist/scanDetailViewModel.test.js +2 -2
- package/dist/scanNarrativeFacts.d.ts +79 -0
- package/dist/scanNarrativeFacts.d.ts.map +1 -0
- package/dist/scanNarrativeFacts.js +18 -0
- package/dist/scanSurfaceCopy.d.ts +26 -0
- package/dist/scanSurfaceCopy.d.ts.map +1 -1
- package/dist/scanSurfaceCopy.js +26 -0
- package/dist/types.d.ts +20 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
import { phraseForFamily, } from "./cardObservationCatalog.js";
|
|
2
|
+
import { aggregateFindingCounts, deriveRiskIndexBand, } from "./scanCardSummary.js";
|
|
3
|
+
import { deriveCardExposureDisplay, } from "./formatCardExposureDisplay.js";
|
|
4
|
+
import { formatCardAreaLabels } from "./formatCardAreaLabels.js";
|
|
5
|
+
import { MERGE_POSTURE_LABEL } from "./riskVocabulary.js";
|
|
6
|
+
import { scanSurfaceCopy } from "./scanSurfaceCopy.js";
|
|
7
|
+
function formatChangedPackagesDisplay(facts) {
|
|
8
|
+
const { primary, others } = facts.changedPackages;
|
|
9
|
+
if (!primary)
|
|
10
|
+
return null;
|
|
11
|
+
if (others.length === 0)
|
|
12
|
+
return primary;
|
|
13
|
+
return `${primary} +${others.length}`;
|
|
14
|
+
}
|
|
15
|
+
function labelRuntimeSurface(facts) {
|
|
16
|
+
const rs = facts.runtimeSurface;
|
|
17
|
+
if (!rs)
|
|
18
|
+
return null;
|
|
19
|
+
return scanSurfaceCopy.narrativeCard.runtimeSurface[rs.kind];
|
|
20
|
+
}
|
|
21
|
+
function labelReachability(facts) {
|
|
22
|
+
const r = facts.reachability;
|
|
23
|
+
if (!r)
|
|
24
|
+
return null;
|
|
25
|
+
return scanSurfaceCopy.narrativeCard.reachability[r.kind];
|
|
26
|
+
}
|
|
27
|
+
function labelBlastRadius(facts) {
|
|
28
|
+
const br = facts.blastRadius;
|
|
29
|
+
if (!br)
|
|
30
|
+
return null;
|
|
31
|
+
return scanSurfaceCopy.narrativeCard.blastRadius[br.level];
|
|
32
|
+
}
|
|
33
|
+
function formatAffectedAreaLabels(facts) {
|
|
34
|
+
const ordered = [];
|
|
35
|
+
for (const area of facts.affectedAreas) {
|
|
36
|
+
const formatted = formatCardAreaLabels([area.label], 1);
|
|
37
|
+
if (formatted[0])
|
|
38
|
+
ordered.push(formatted[0]);
|
|
39
|
+
if (ordered.length >= 2)
|
|
40
|
+
break;
|
|
41
|
+
}
|
|
42
|
+
return ordered;
|
|
43
|
+
}
|
|
44
|
+
function selectPrimaryInsight(facts) {
|
|
45
|
+
const changedGuidance = facts.reviewerGuidance.find((g) => g.scope === "changed" && g.message.trim());
|
|
46
|
+
if (changedGuidance)
|
|
47
|
+
return changedGuidance.message.trim();
|
|
48
|
+
const insight = facts.reviewerGuidance.find((g) => g.kind === "insight" && g.message.trim());
|
|
49
|
+
if (insight)
|
|
50
|
+
return insight.message.trim();
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
function selectSecondaryLines(facts, exclude) {
|
|
54
|
+
const lines = [];
|
|
55
|
+
for (const g of facts.reviewerGuidance) {
|
|
56
|
+
const msg = g.message.trim();
|
|
57
|
+
if (!msg || msg === exclude)
|
|
58
|
+
continue;
|
|
59
|
+
lines.push(msg);
|
|
60
|
+
if (lines.length >= 2)
|
|
61
|
+
break;
|
|
62
|
+
}
|
|
63
|
+
return lines;
|
|
64
|
+
}
|
|
65
|
+
function repositoryContextPhrases(facts) {
|
|
66
|
+
const phrases = [];
|
|
67
|
+
const seen = new Set();
|
|
68
|
+
for (const ctx of facts.repositoryContext) {
|
|
69
|
+
const phrase = phraseForFamily(ctx.family);
|
|
70
|
+
if (seen.has(phrase))
|
|
71
|
+
continue;
|
|
72
|
+
seen.add(phrase);
|
|
73
|
+
phrases.push(phrase);
|
|
74
|
+
if (phrases.length >= 3)
|
|
75
|
+
break;
|
|
76
|
+
}
|
|
77
|
+
return phrases;
|
|
78
|
+
}
|
|
79
|
+
function composeContextLine(facts) {
|
|
80
|
+
const parts = [];
|
|
81
|
+
const runtime = labelRuntimeSurface(facts);
|
|
82
|
+
const reach = labelReachability(facts);
|
|
83
|
+
const blast = labelBlastRadius(facts);
|
|
84
|
+
if (runtime)
|
|
85
|
+
parts.push(runtime);
|
|
86
|
+
if (reach)
|
|
87
|
+
parts.push(reach);
|
|
88
|
+
if (blast)
|
|
89
|
+
parts.push(blast);
|
|
90
|
+
const areas = formatAffectedAreaLabels(facts);
|
|
91
|
+
if (areas.length > 0) {
|
|
92
|
+
parts.push(areas.join(scanSurfaceCopy.narrativeCard.areasSeparator));
|
|
93
|
+
}
|
|
94
|
+
if (parts.length === 0)
|
|
95
|
+
return null;
|
|
96
|
+
return parts.join(scanSurfaceCopy.narrativeCard.contextSeparator);
|
|
97
|
+
}
|
|
98
|
+
function buildLegacyObservations(facts, primaryInsight) {
|
|
99
|
+
const repoPhrases = repositoryContextPhrases(facts);
|
|
100
|
+
const secondary = selectSecondaryLines(facts, primaryInsight);
|
|
101
|
+
if (primaryInsight) {
|
|
102
|
+
return {
|
|
103
|
+
operationalObservations: repoPhrases.slice(0, 1),
|
|
104
|
+
supportingLine: repoPhrases[0] && repoPhrases[0] !== primaryInsight
|
|
105
|
+
? repoPhrases[0]
|
|
106
|
+
: (secondary[0] ?? null),
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
if (repoPhrases.length === 0) {
|
|
110
|
+
return { operationalObservations: [], supportingLine: null };
|
|
111
|
+
}
|
|
112
|
+
return {
|
|
113
|
+
operationalObservations: repoPhrases.slice(0, 3),
|
|
114
|
+
supportingLine: repoPhrases.length === 1 ? (secondary[0] ?? null) : null,
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Dashboard card presentation DTO from consumer-agnostic facts.
|
|
119
|
+
*/
|
|
120
|
+
export function presentScanCardSummary(facts, options = {}) {
|
|
121
|
+
const pipelineStatus = options.pipelineStatus ?? "done";
|
|
122
|
+
const emptyPresentationFields = {
|
|
123
|
+
narrativeMode: facts.availability.mode,
|
|
124
|
+
codeIntelligenceAvailable: facts.availability.codeIntelligenceAvailable,
|
|
125
|
+
changedPackagesDisplay: null,
|
|
126
|
+
runtimeSurfaceLabel: null,
|
|
127
|
+
reachabilityLabel: null,
|
|
128
|
+
blastRadiusLabel: null,
|
|
129
|
+
affectedAreas: [],
|
|
130
|
+
primaryInsight: null,
|
|
131
|
+
structuralOnlyDisclaimer: null,
|
|
132
|
+
};
|
|
133
|
+
if (pipelineStatus === "queued" || pipelineStatus === "running") {
|
|
134
|
+
return {
|
|
135
|
+
mergePosture: null,
|
|
136
|
+
riskIndex: null,
|
|
137
|
+
riskIndexBand: null,
|
|
138
|
+
headline: scanSurfaceCopy.pipeline.scanRunning,
|
|
139
|
+
summaryLine: "Waiting for results…",
|
|
140
|
+
findingCounts: null,
|
|
141
|
+
topAffectedAreas: [],
|
|
142
|
+
operationalObservations: [],
|
|
143
|
+
supportingLine: null,
|
|
144
|
+
...emptyPresentationFields,
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
if (pipelineStatus === "failed") {
|
|
148
|
+
return {
|
|
149
|
+
mergePosture: null,
|
|
150
|
+
riskIndex: null,
|
|
151
|
+
riskIndexBand: null,
|
|
152
|
+
headline: scanSurfaceCopy.pipeline.analysisIncomplete,
|
|
153
|
+
summaryLine: null,
|
|
154
|
+
findingCounts: null,
|
|
155
|
+
topAffectedAreas: [],
|
|
156
|
+
operationalObservations: [],
|
|
157
|
+
supportingLine: null,
|
|
158
|
+
...emptyPresentationFields,
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
const posture = facts.mergePosture;
|
|
162
|
+
const riskIndex = facts.riskIndex;
|
|
163
|
+
const riskIndexBand = deriveRiskIndexBand(riskIndex);
|
|
164
|
+
const headline = posture
|
|
165
|
+
? MERGE_POSTURE_LABEL[posture]
|
|
166
|
+
: scanSurfaceCopy.checkRun.mergePostureUnavailable;
|
|
167
|
+
const findingCounts = options.findings
|
|
168
|
+
? aggregateFindingCounts(options.findings)
|
|
169
|
+
: null;
|
|
170
|
+
const changedPackagesDisplay = formatChangedPackagesDisplay(facts);
|
|
171
|
+
const runtimeSurfaceLabel = labelRuntimeSurface(facts);
|
|
172
|
+
const reachabilityLabel = labelReachability(facts);
|
|
173
|
+
const blastRadiusLabel = labelBlastRadius(facts);
|
|
174
|
+
const affectedAreas = formatAffectedAreaLabels(facts);
|
|
175
|
+
const contextLine = composeContextLine(facts);
|
|
176
|
+
const structuralOnlyDisclaimer = facts.availability.mode === "graph_fallback" &&
|
|
177
|
+
!facts.availability.tiersPresent.tier1
|
|
178
|
+
? scanSurfaceCopy.narrativeCard.structuralOnlyDisclaimer
|
|
179
|
+
: null;
|
|
180
|
+
const insightMessage = selectPrimaryInsight(facts);
|
|
181
|
+
const primaryInsight = insightMessage ??
|
|
182
|
+
(facts.availability.mode !== "graph_fallback" ? contextLine : null);
|
|
183
|
+
const { operationalObservations, supportingLine } = buildLegacyObservations(facts, primaryInsight);
|
|
184
|
+
return {
|
|
185
|
+
mergePosture: posture,
|
|
186
|
+
riskIndex,
|
|
187
|
+
riskIndexBand,
|
|
188
|
+
headline,
|
|
189
|
+
summaryLine: null,
|
|
190
|
+
findingCounts,
|
|
191
|
+
topAffectedAreas: affectedAreas,
|
|
192
|
+
operationalObservations,
|
|
193
|
+
supportingLine,
|
|
194
|
+
narrativeMode: facts.availability.mode,
|
|
195
|
+
codeIntelligenceAvailable: facts.availability.codeIntelligenceAvailable,
|
|
196
|
+
changedPackagesDisplay,
|
|
197
|
+
runtimeSurfaceLabel,
|
|
198
|
+
reachabilityLabel,
|
|
199
|
+
blastRadiusLabel,
|
|
200
|
+
affectedAreas,
|
|
201
|
+
primaryInsight,
|
|
202
|
+
structuralOnlyDisclaimer,
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
export function exposureFromFacts(facts) {
|
|
206
|
+
return deriveCardExposureDisplay(facts.riskIndex) ?? null;
|
|
207
|
+
}
|
|
@@ -71,7 +71,7 @@ export declare const productMessaging: {
|
|
|
71
71
|
readonly exposure: "Exposure indicates how broadly the upgrade touches runtime-relevant application areas.";
|
|
72
72
|
readonly exposureCategoriesLead: "On each scanned card, exposure reads as one of:";
|
|
73
73
|
readonly exposureCategories: readonly string[];
|
|
74
|
-
readonly cardBody: "Below the verdict, scanned cards
|
|
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.";
|
|
75
75
|
};
|
|
76
76
|
};
|
|
77
77
|
/** Illustrative scan-card example for homepage proof band and getting-started. */
|
package/dist/productMessaging.js
CHANGED
|
@@ -86,7 +86,7 @@ export const productMessaging = {
|
|
|
86
86
|
exposure: "Exposure indicates how broadly the upgrade touches runtime-relevant application areas.",
|
|
87
87
|
exposureCategoriesLead: "On each scanned card, exposure reads as one of:",
|
|
88
88
|
exposureCategories: CARD_EXPOSURE_CATEGORY_LABELS,
|
|
89
|
-
cardBody: "Below the verdict, scanned cards
|
|
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.",
|
|
90
90
|
},
|
|
91
91
|
};
|
|
92
92
|
/** Illustrative scan-card example for homepage proof band and getting-started. */
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import type { BlastRadiusLevel, ReachabilityKind, RuntimeSurfaceKind } from "./scanNarrativeFacts.js";
|
|
3
|
+
declare const looseSurfaceSchema: z.ZodUnion<readonly [z.ZodEnum<{
|
|
4
|
+
unknown: "unknown";
|
|
5
|
+
runtime: "runtime";
|
|
6
|
+
build: "build";
|
|
7
|
+
test: "test";
|
|
8
|
+
}>, z.ZodString, z.ZodObject<{
|
|
9
|
+
kind: z.ZodString;
|
|
10
|
+
}, z.core.$loose>]>;
|
|
11
|
+
declare const looseReachabilitySchema: z.ZodUnion<readonly [z.ZodEnum<{
|
|
12
|
+
unknown: "unknown";
|
|
13
|
+
on_runtime_paths: "on_runtime_paths";
|
|
14
|
+
build_only: "build_only";
|
|
15
|
+
test_only: "test_only";
|
|
16
|
+
unreachable: "unreachable";
|
|
17
|
+
}>, z.ZodString, z.ZodObject<{
|
|
18
|
+
kind: z.ZodString;
|
|
19
|
+
}, z.core.$loose>]>;
|
|
20
|
+
export declare const repoIntelligenceSchema: z.ZodObject<{
|
|
21
|
+
packages: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
22
|
+
runtimeSurface: z.ZodOptional<z.ZodUnion<readonly [z.ZodEnum<{
|
|
23
|
+
unknown: "unknown";
|
|
24
|
+
runtime: "runtime";
|
|
25
|
+
build: "build";
|
|
26
|
+
test: "test";
|
|
27
|
+
}>, z.ZodString, z.ZodObject<{
|
|
28
|
+
kind: z.ZodString;
|
|
29
|
+
}, z.core.$loose>]>>;
|
|
30
|
+
reachability: z.ZodOptional<z.ZodUnion<readonly [z.ZodEnum<{
|
|
31
|
+
unknown: "unknown";
|
|
32
|
+
on_runtime_paths: "on_runtime_paths";
|
|
33
|
+
build_only: "build_only";
|
|
34
|
+
test_only: "test_only";
|
|
35
|
+
unreachable: "unreachable";
|
|
36
|
+
}>, z.ZodString, z.ZodObject<{
|
|
37
|
+
kind: z.ZodString;
|
|
38
|
+
}, z.core.$loose>]>>;
|
|
39
|
+
packageUsage: z.ZodOptional<z.ZodObject<{
|
|
40
|
+
packageName: z.ZodOptional<z.ZodString>;
|
|
41
|
+
package: z.ZodOptional<z.ZodString>;
|
|
42
|
+
files: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
43
|
+
paths: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
44
|
+
criticalPaths: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
45
|
+
areas: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
46
|
+
}, z.core.$loose>>;
|
|
47
|
+
usage: z.ZodOptional<z.ZodObject<{
|
|
48
|
+
packageName: z.ZodOptional<z.ZodString>;
|
|
49
|
+
package: z.ZodOptional<z.ZodString>;
|
|
50
|
+
files: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
51
|
+
paths: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
52
|
+
criticalPaths: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
53
|
+
areas: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
54
|
+
}, z.core.$loose>>;
|
|
55
|
+
areas: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
56
|
+
hotspots: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
57
|
+
packageName: z.ZodOptional<z.ZodString>;
|
|
58
|
+
paths: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
59
|
+
depth: z.ZodOptional<z.ZodNumber>;
|
|
60
|
+
}, z.core.$loose>>>;
|
|
61
|
+
}, z.core.$loose>>>;
|
|
62
|
+
packageUsage: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
63
|
+
packageName: z.ZodOptional<z.ZodString>;
|
|
64
|
+
package: z.ZodOptional<z.ZodString>;
|
|
65
|
+
files: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
66
|
+
paths: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
67
|
+
criticalPaths: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
68
|
+
areas: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
69
|
+
}, z.core.$loose>>>;
|
|
70
|
+
blastRadius: z.ZodOptional<z.ZodObject<{
|
|
71
|
+
level: z.ZodOptional<z.ZodEnum<{
|
|
72
|
+
moderate: "moderate";
|
|
73
|
+
narrow: "narrow";
|
|
74
|
+
wide: "wide";
|
|
75
|
+
}>>;
|
|
76
|
+
factors: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
77
|
+
changedPackageCount: z.ZodOptional<z.ZodNumber>;
|
|
78
|
+
}, z.core.$loose>>;
|
|
79
|
+
runtimeSurface: z.ZodOptional<z.ZodUnion<readonly [z.ZodEnum<{
|
|
80
|
+
unknown: "unknown";
|
|
81
|
+
runtime: "runtime";
|
|
82
|
+
build: "build";
|
|
83
|
+
test: "test";
|
|
84
|
+
}>, z.ZodString, z.ZodObject<{
|
|
85
|
+
kind: z.ZodString;
|
|
86
|
+
}, z.core.$loose>]>>;
|
|
87
|
+
reachability: z.ZodOptional<z.ZodUnion<readonly [z.ZodEnum<{
|
|
88
|
+
unknown: "unknown";
|
|
89
|
+
on_runtime_paths: "on_runtime_paths";
|
|
90
|
+
build_only: "build_only";
|
|
91
|
+
test_only: "test_only";
|
|
92
|
+
unreachable: "unreachable";
|
|
93
|
+
}>, z.ZodString, z.ZodObject<{
|
|
94
|
+
kind: z.ZodString;
|
|
95
|
+
}, z.core.$loose>]>>;
|
|
96
|
+
applicationAreas: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
97
|
+
id: z.ZodString;
|
|
98
|
+
label: z.ZodString;
|
|
99
|
+
}, z.core.$loose>>>;
|
|
100
|
+
affectedAreas: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
101
|
+
id: z.ZodString;
|
|
102
|
+
label: z.ZodString;
|
|
103
|
+
}, z.core.$loose>>>;
|
|
104
|
+
hotspots: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
105
|
+
packageName: z.ZodString;
|
|
106
|
+
source: z.ZodOptional<z.ZodEnum<{
|
|
107
|
+
code: "code";
|
|
108
|
+
graph: "graph";
|
|
109
|
+
}>>;
|
|
110
|
+
depth: z.ZodOptional<z.ZodNumber>;
|
|
111
|
+
paths: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
112
|
+
}, z.core.$loose>>>;
|
|
113
|
+
frameworks: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
114
|
+
}, z.core.$loose>;
|
|
115
|
+
export type RepoIntelligence = z.infer<typeof repoIntelligenceSchema>;
|
|
116
|
+
export declare function parseRepoIntelligence(raw: unknown): RepoIntelligence | null;
|
|
117
|
+
export declare function normalizeRuntimeSurfaceKind(raw: string | undefined): RuntimeSurfaceKind;
|
|
118
|
+
export declare function normalizeReachabilityKind(raw: string | undefined): ReachabilityKind;
|
|
119
|
+
export declare function readSurfaceFromLoose(value: z.infer<typeof looseSurfaceSchema> | undefined): RuntimeSurfaceKind | null;
|
|
120
|
+
export declare function readReachabilityFromLoose(value: z.infer<typeof looseReachabilitySchema> | undefined): ReachabilityKind | null;
|
|
121
|
+
export declare function readBlastLevel(level: BlastRadiusLevel | undefined): BlastRadiusLevel | null;
|
|
122
|
+
export {};
|
|
123
|
+
//# sourceMappingURL=repoIntelligenceSchema.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"repoIntelligenceSchema.d.ts","sourceRoot":"","sources":["../src/repoIntelligenceSchema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EACV,gBAAgB,EAChB,gBAAgB,EAChB,kBAAkB,EACnB,MAAM,yBAAyB,CAAC;AAcjC,QAAA,MAAM,kBAAkB;;;;;;;mBAItB,CAAC;AAEH,QAAA,MAAM,uBAAuB;;;;;;;;mBAI3B,CAAC;AAyCH,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBA8BnB,CAAC;AAEjB,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,sBAAsB,CAAC,CAAC;AAEtE,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,OAAO,GAAG,gBAAgB,GAAG,IAAI,CAc3E;AAuBD,wBAAgB,2BAA2B,CACzC,GAAG,EAAE,MAAM,GAAG,SAAS,GACtB,kBAAkB,CAUpB;AAED,wBAAgB,yBAAyB,CACvC,GAAG,EAAE,MAAM,GAAG,SAAS,GACtB,gBAAgB,CAgBlB;AAED,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,GAAG,SAAS,GACpD,kBAAkB,GAAG,IAAI,CAO3B;AAED,wBAAgB,yBAAyB,CACvC,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,uBAAuB,CAAC,GAAG,SAAS,GACzD,gBAAgB,GAAG,IAAI,CAOzB;AAED,wBAAgB,cAAc,CAC5B,KAAK,EAAE,gBAAgB,GAAG,SAAS,GAClC,gBAAgB,GAAG,IAAI,CAKzB"}
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
const surfaceKindSchema = z.enum(["runtime", "build", "test", "unknown"]);
|
|
3
|
+
const reachabilityKindSchema = z.enum([
|
|
4
|
+
"on_runtime_paths",
|
|
5
|
+
"build_only",
|
|
6
|
+
"test_only",
|
|
7
|
+
"unreachable",
|
|
8
|
+
"unknown",
|
|
9
|
+
]);
|
|
10
|
+
const blastLevelSchema = z.enum(["narrow", "moderate", "wide"]);
|
|
11
|
+
const looseSurfaceSchema = z.union([
|
|
12
|
+
surfaceKindSchema,
|
|
13
|
+
z.string(),
|
|
14
|
+
z.object({ kind: z.string() }).passthrough(),
|
|
15
|
+
]);
|
|
16
|
+
const looseReachabilitySchema = z.union([
|
|
17
|
+
reachabilityKindSchema,
|
|
18
|
+
z.string(),
|
|
19
|
+
z.object({ kind: z.string() }).passthrough(),
|
|
20
|
+
]);
|
|
21
|
+
const packageUsageEntrySchema = z
|
|
22
|
+
.object({
|
|
23
|
+
packageName: z.string().optional(),
|
|
24
|
+
package: z.string().optional(),
|
|
25
|
+
files: z.array(z.string()).optional(),
|
|
26
|
+
paths: z.array(z.string()).optional(),
|
|
27
|
+
criticalPaths: z.array(z.string()).optional(),
|
|
28
|
+
areas: z.array(z.string()).optional(),
|
|
29
|
+
})
|
|
30
|
+
.passthrough();
|
|
31
|
+
const packageIntelSchema = z
|
|
32
|
+
.object({
|
|
33
|
+
runtimeSurface: looseSurfaceSchema.optional(),
|
|
34
|
+
reachability: looseReachabilitySchema.optional(),
|
|
35
|
+
packageUsage: packageUsageEntrySchema.optional(),
|
|
36
|
+
usage: packageUsageEntrySchema.optional(),
|
|
37
|
+
areas: z.array(z.string()).optional(),
|
|
38
|
+
hotspots: z
|
|
39
|
+
.array(z
|
|
40
|
+
.object({
|
|
41
|
+
packageName: z.string().optional(),
|
|
42
|
+
paths: z.array(z.string()).optional(),
|
|
43
|
+
depth: z.number().optional(),
|
|
44
|
+
})
|
|
45
|
+
.passthrough())
|
|
46
|
+
.optional(),
|
|
47
|
+
})
|
|
48
|
+
.passthrough();
|
|
49
|
+
const areaSchema = z
|
|
50
|
+
.object({
|
|
51
|
+
id: z.string(),
|
|
52
|
+
label: z.string(),
|
|
53
|
+
})
|
|
54
|
+
.passthrough();
|
|
55
|
+
export const repoIntelligenceSchema = z
|
|
56
|
+
.object({
|
|
57
|
+
packages: z.record(z.string(), packageIntelSchema).optional(),
|
|
58
|
+
packageUsage: z.array(packageUsageEntrySchema).optional(),
|
|
59
|
+
blastRadius: z
|
|
60
|
+
.object({
|
|
61
|
+
level: blastLevelSchema.optional(),
|
|
62
|
+
factors: z.array(z.string()).optional(),
|
|
63
|
+
changedPackageCount: z.number().optional(),
|
|
64
|
+
})
|
|
65
|
+
.passthrough()
|
|
66
|
+
.optional(),
|
|
67
|
+
runtimeSurface: looseSurfaceSchema.optional(),
|
|
68
|
+
reachability: looseReachabilitySchema.optional(),
|
|
69
|
+
applicationAreas: z.array(areaSchema).optional(),
|
|
70
|
+
affectedAreas: z.array(areaSchema).optional(),
|
|
71
|
+
hotspots: z
|
|
72
|
+
.array(z
|
|
73
|
+
.object({
|
|
74
|
+
packageName: z.string(),
|
|
75
|
+
source: z.enum(["code", "graph"]).optional(),
|
|
76
|
+
depth: z.number().optional(),
|
|
77
|
+
paths: z.array(z.string()).optional(),
|
|
78
|
+
})
|
|
79
|
+
.passthrough())
|
|
80
|
+
.optional(),
|
|
81
|
+
frameworks: z.array(z.string()).optional(),
|
|
82
|
+
})
|
|
83
|
+
.passthrough();
|
|
84
|
+
export function parseRepoIntelligence(raw) {
|
|
85
|
+
if (raw == null || typeof raw !== "object")
|
|
86
|
+
return null;
|
|
87
|
+
const parsed = repoIntelligenceSchema.safeParse(raw);
|
|
88
|
+
if (!parsed.success)
|
|
89
|
+
return null;
|
|
90
|
+
const value = parsed.data;
|
|
91
|
+
if (Object.keys(value).length === 0)
|
|
92
|
+
return null;
|
|
93
|
+
if (Object.keys(value).length === 1 &&
|
|
94
|
+
value.packages &&
|
|
95
|
+
Object.keys(value.packages).length === 0) {
|
|
96
|
+
return null;
|
|
97
|
+
}
|
|
98
|
+
return value;
|
|
99
|
+
}
|
|
100
|
+
const RUNTIME_SURFACE_ALIASES = [
|
|
101
|
+
[/\bruntime\b/i, "runtime"],
|
|
102
|
+
[/\bproduction\b/i, "runtime"],
|
|
103
|
+
[/\bapi\b/i, "runtime"],
|
|
104
|
+
[/\bbuild\b/i, "build"],
|
|
105
|
+
[/\bdev(?:elopment)?\b/i, "build"],
|
|
106
|
+
[/\btypescript\b/i, "build"],
|
|
107
|
+
[/\btest\b/i, "test"],
|
|
108
|
+
[/\bvitest\b/i, "test"],
|
|
109
|
+
[/\bjest\b/i, "test"],
|
|
110
|
+
];
|
|
111
|
+
const REACHABILITY_ALIASES = [
|
|
112
|
+
[/\bon[_\s-]?runtime/i, "on_runtime_paths"],
|
|
113
|
+
[/\bruntime[_\s-]?path/i, "on_runtime_paths"],
|
|
114
|
+
[/\bdirect\b/i, "on_runtime_paths"],
|
|
115
|
+
[/\bbuild[_\s-]?only/i, "build_only"],
|
|
116
|
+
[/\btest[_\s-]?only/i, "test_only"],
|
|
117
|
+
[/\bunreachable\b/i, "unreachable"],
|
|
118
|
+
];
|
|
119
|
+
export function normalizeRuntimeSurfaceKind(raw) {
|
|
120
|
+
if (!raw?.trim())
|
|
121
|
+
return "unknown";
|
|
122
|
+
const t = raw.trim().toLowerCase();
|
|
123
|
+
if (t === "runtime" || t === "build" || t === "test" || t === "unknown") {
|
|
124
|
+
return t;
|
|
125
|
+
}
|
|
126
|
+
for (const [re, kind] of RUNTIME_SURFACE_ALIASES) {
|
|
127
|
+
if (re.test(t))
|
|
128
|
+
return kind;
|
|
129
|
+
}
|
|
130
|
+
return "unknown";
|
|
131
|
+
}
|
|
132
|
+
export function normalizeReachabilityKind(raw) {
|
|
133
|
+
if (!raw?.trim())
|
|
134
|
+
return "unknown";
|
|
135
|
+
const t = raw.trim().toLowerCase();
|
|
136
|
+
if (t === "on_runtime_paths" ||
|
|
137
|
+
t === "build_only" ||
|
|
138
|
+
t === "test_only" ||
|
|
139
|
+
t === "unreachable" ||
|
|
140
|
+
t === "unknown") {
|
|
141
|
+
return t;
|
|
142
|
+
}
|
|
143
|
+
for (const [re, kind] of REACHABILITY_ALIASES) {
|
|
144
|
+
if (re.test(t))
|
|
145
|
+
return kind;
|
|
146
|
+
}
|
|
147
|
+
return "unknown";
|
|
148
|
+
}
|
|
149
|
+
export function readSurfaceFromLoose(value) {
|
|
150
|
+
if (value == null)
|
|
151
|
+
return null;
|
|
152
|
+
if (typeof value === "string")
|
|
153
|
+
return normalizeRuntimeSurfaceKind(value);
|
|
154
|
+
if (typeof value === "object" && "kind" in value) {
|
|
155
|
+
return normalizeRuntimeSurfaceKind(String(value.kind));
|
|
156
|
+
}
|
|
157
|
+
return null;
|
|
158
|
+
}
|
|
159
|
+
export function readReachabilityFromLoose(value) {
|
|
160
|
+
if (value == null)
|
|
161
|
+
return null;
|
|
162
|
+
if (typeof value === "string")
|
|
163
|
+
return normalizeReachabilityKind(value);
|
|
164
|
+
if (typeof value === "object" && "kind" in value) {
|
|
165
|
+
return normalizeReachabilityKind(String(value.kind));
|
|
166
|
+
}
|
|
167
|
+
return null;
|
|
168
|
+
}
|
|
169
|
+
export function readBlastLevel(level) {
|
|
170
|
+
if (level === "narrow" || level === "moderate" || level === "wide") {
|
|
171
|
+
return level;
|
|
172
|
+
}
|
|
173
|
+
return null;
|
|
174
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { CatalogPhrase } from "./cardObservationCatalog.js";
|
|
2
|
+
import type { NarrativeAvailabilityMode } from "./scanNarrativeFacts.js";
|
|
2
3
|
import { type MergePosture } from "./riskVocabulary.js";
|
|
3
4
|
import type { Finding, ScanResult } from "./types.js";
|
|
4
5
|
export type ScanPipelineStatus = "queued" | "running" | "done" | "failed";
|
|
@@ -18,12 +19,21 @@ export type ScanCardSummary = {
|
|
|
18
19
|
/** @deprecated Use operationalObservations */
|
|
19
20
|
summaryLine: string | null;
|
|
20
21
|
findingCounts: FindingCountSummary | null;
|
|
21
|
-
/** @deprecated Use
|
|
22
|
+
/** @deprecated Use affectedAreas */
|
|
22
23
|
topAffectedAreas: string[];
|
|
23
|
-
/** Catalog-mapped topology observations (0–3). */
|
|
24
|
+
/** Catalog-mapped topology observations (0–3). Tier 3 repo context — legacy wire field. */
|
|
24
25
|
operationalObservations: CatalogPhrase[];
|
|
25
26
|
/** Optional quiet subline when exactly one observation is shown. */
|
|
26
27
|
supportingLine: string | null;
|
|
28
|
+
narrativeMode: NarrativeAvailabilityMode;
|
|
29
|
+
codeIntelligenceAvailable: boolean;
|
|
30
|
+
changedPackagesDisplay: string | null;
|
|
31
|
+
runtimeSurfaceLabel: string | null;
|
|
32
|
+
reachabilityLabel: string | null;
|
|
33
|
+
blastRadiusLabel: string | null;
|
|
34
|
+
affectedAreas: string[];
|
|
35
|
+
primaryInsight: string | null;
|
|
36
|
+
structuralOnlyDisclaimer: string | null;
|
|
27
37
|
};
|
|
28
38
|
export declare const SCAN_CARD_SCANNING_SUMMARY = "Waiting for results\u2026";
|
|
29
39
|
export type PipelineCompletionEvidence = {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scanCardSummary.d.ts","sourceRoot":"","sources":["../src/scanCardSummary.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"scanCardSummary.d.ts","sourceRoot":"","sources":["../src/scanCardSummary.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAGjE,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,yBAAyB,CAAC;AACzE,OAAO,EAGL,KAAK,YAAY,EAClB,MAAM,qBAAqB,CAAC;AAE7B,OAAO,KAAK,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAEtD,MAAM,MAAM,kBAAkB,GAAG,QAAQ,GAAG,SAAS,GAAG,MAAM,GAAG,QAAQ,CAAC;AAE1E,MAAM,MAAM,yBAAyB,GACjC,aAAa,GACb,UAAU,GACV,iBAAiB,GACjB,OAAO,GACP,OAAO,CAAC;AAEZ,MAAM,MAAM,aAAa,GAAG,KAAK,GAAG,QAAQ,GAAG,MAAM,CAAC;AAEtD,MAAM,MAAM,mBAAmB,GAAG;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;CACb,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC5B,YAAY,EAAE,YAAY,GAAG,IAAI,CAAC;IAClC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,aAAa,EAAE,aAAa,GAAG,IAAI,CAAC;IACpC,QAAQ,EAAE,MAAM,CAAC;IACjB,8CAA8C;IAC9C,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,aAAa,EAAE,mBAAmB,GAAG,IAAI,CAAC;IAC1C,oCAAoC;IACpC,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,2FAA2F;IAC3F,uBAAuB,EAAE,aAAa,EAAE,CAAC;IACzC,oEAAoE;IACpE,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,aAAa,EAAE,yBAAyB,CAAC;IACzC,yBAAyB,EAAE,OAAO,CAAC;IACnC,sBAAsB,EAAE,MAAM,GAAG,IAAI,CAAC;IACtC,mBAAmB,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,wBAAwB,EAAE,MAAM,GAAG,IAAI,CAAC;CACzC,CAAC;AAGF,eAAO,MAAM,0BAA0B,8BAAyB,CAAC;AAEjE,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;AAED,8EAA8E;AAC9E,wBAAgB,yBAAyB,CACvC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAC9B,OAAO,CAST;AAED,wEAAwE;AACxE,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAUvE;AAED,mFAAmF;AACnF,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAC/B,aAAa,GAAG,IAAI,CAKtB;AAED,wBAAgB,sBAAsB,CACpC,QAAQ,EAAE,OAAO,EAAE,GAAG,IAAI,GAAG,SAAS,GACrC,mBAAmB,CAgBrB;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,UAAU,GAAG,IAAI,GAAG,SAAS,EACrC,cAAc,EAAE,kBAAkB,GACjC,eAAe,CAyBjB;AAED,wEAAwE;AACxE,wBAAgB,gBAAgB,IAAI,MAAM,CAEzC;AAED,2FAA2F;AAC3F,wBAAgB,qCAAqC,CACnD,QAAQ,EAAE,MAAM,GAAG,IAAI,EACvB,UAAU,EAAE,MAAM,GAAG,IAAI,EACzB,WAAW,EAAE,MAAM,GAAG,IAAI,EAC1B,cAAc,EAAE,kBAAkB,GACjC,eAAe,CAuBjB;AAED,MAAM,MAAM,sBAAsB,GAAG;IACnC,cAAc,EAAE,MAAM,CAAC;IACvB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,MAAM,EAAE,UAAU,GAAG,IAAI,CAAC;IAC1B,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B,CAAC;AAEF;;GAEG;AACH,wBAAgB,wBAAwB,CACtC,KAAK,EAAE,sBAAsB,GAC5B,eAAe,CAkDjB"}
|
package/dist/scanCardSummary.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { deriveScanNarrative } from "./deriveScanNarrative.js";
|
|
2
|
+
import { presentScanCardSummary } from "./presentScanCardSummary.js";
|
|
3
|
+
import { mergePostureFromDecision, } from "./riskVocabulary.js";
|
|
3
4
|
import { scanSurfaceCopy } from "./scanSurfaceCopy.js";
|
|
4
|
-
import { selectTopAffectedAreas } from "./selectTopAffectedAreas.js";
|
|
5
5
|
const STALE_SUBLINE = "Based on earlier commit";
|
|
6
6
|
export const SCAN_CARD_SCANNING_SUMMARY = "Waiting for results…";
|
|
7
7
|
function normalizePipelineStatus(status) {
|
|
@@ -59,7 +59,8 @@ export function isPipelineCardSummary(summary) {
|
|
|
59
59
|
summary.riskIndex === null &&
|
|
60
60
|
(summary.headline === scanSurfaceCopy.pipeline.scanRunning ||
|
|
61
61
|
summary.headline === scanSurfaceCopy.pipeline.analysisIncomplete ||
|
|
62
|
-
summary.headline === scanSurfaceCopy.pipeline.scanUnavailable)
|
|
62
|
+
summary.headline === scanSurfaceCopy.pipeline.scanUnavailable) &&
|
|
63
|
+
summary.narrativeMode === "denormalized");
|
|
63
64
|
}
|
|
64
65
|
/** Single source for risk index color bands (aligns with decision score bands). */
|
|
65
66
|
export function deriveRiskIndexBand(score) {
|
|
@@ -101,68 +102,26 @@ export function aggregateFindingCounts(findings) {
|
|
|
101
102
|
*/
|
|
102
103
|
export function deriveScanCardSummary(result, pipelineStatus) {
|
|
103
104
|
if (pipelineStatus === "queued" || pipelineStatus === "running") {
|
|
104
|
-
return {
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
riskIndexBand: null,
|
|
108
|
-
headline: scanSurfaceCopy.pipeline.scanRunning,
|
|
109
|
-
summaryLine: SCAN_CARD_SCANNING_SUMMARY,
|
|
110
|
-
findingCounts: null,
|
|
111
|
-
topAffectedAreas: [],
|
|
112
|
-
operationalObservations: [],
|
|
113
|
-
supportingLine: null,
|
|
114
|
-
};
|
|
105
|
+
return presentScanCardSummary(deriveScanNarrative(null), {
|
|
106
|
+
pipelineStatus,
|
|
107
|
+
});
|
|
115
108
|
}
|
|
116
109
|
if (pipelineStatus === "failed") {
|
|
117
|
-
return {
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
riskIndexBand: null,
|
|
121
|
-
headline: scanSurfaceCopy.pipeline.analysisIncomplete,
|
|
122
|
-
summaryLine: null,
|
|
123
|
-
findingCounts: null,
|
|
124
|
-
topAffectedAreas: [],
|
|
125
|
-
operationalObservations: [],
|
|
126
|
-
supportingLine: null,
|
|
127
|
-
};
|
|
110
|
+
return presentScanCardSummary(deriveScanNarrative(null), {
|
|
111
|
+
pipelineStatus: "failed",
|
|
112
|
+
});
|
|
128
113
|
}
|
|
129
114
|
if (!result) {
|
|
130
115
|
return {
|
|
131
|
-
|
|
132
|
-
riskIndex: null,
|
|
133
|
-
riskIndexBand: null,
|
|
116
|
+
...presentScanCardSummary(deriveScanNarrative(null), { pipelineStatus }),
|
|
134
117
|
headline: scanSurfaceCopy.pipeline.scanUnavailable,
|
|
135
|
-
summaryLine: null,
|
|
136
|
-
findingCounts: null,
|
|
137
|
-
topAffectedAreas: [],
|
|
138
|
-
operationalObservations: [],
|
|
139
|
-
supportingLine: null,
|
|
140
118
|
};
|
|
141
119
|
}
|
|
142
|
-
const
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
const headline = posture
|
|
147
|
-
? MERGE_POSTURE_LABEL[posture]
|
|
148
|
-
: scanSurfaceCopy.checkRun.mergePostureUnavailable;
|
|
149
|
-
const topAffectedAreas = selectTopAffectedAreas(result, { max: 2 });
|
|
150
|
-
const { operationalObservations, supportingLine } = deriveCardOperationalObservations(result, {
|
|
151
|
-
mergePosture: posture,
|
|
152
|
-
hasFullResult: true,
|
|
153
|
-
max: 3,
|
|
120
|
+
const facts = deriveScanNarrative(result);
|
|
121
|
+
return presentScanCardSummary(facts, {
|
|
122
|
+
pipelineStatus,
|
|
123
|
+
findings: result.findings,
|
|
154
124
|
});
|
|
155
|
-
return {
|
|
156
|
-
mergePosture: posture,
|
|
157
|
-
riskIndex,
|
|
158
|
-
riskIndexBand,
|
|
159
|
-
headline,
|
|
160
|
-
summaryLine: null,
|
|
161
|
-
findingCounts,
|
|
162
|
-
topAffectedAreas,
|
|
163
|
-
operationalObservations,
|
|
164
|
-
supportingLine,
|
|
165
|
-
};
|
|
166
125
|
}
|
|
167
126
|
/** Subline appended when scan results are stale (head SHA mismatch). */
|
|
168
127
|
export function staleScanSubline() {
|