@mergesignal/shared 0.2.7 → 0.2.8
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/actionsStepSummary.d.ts.map +1 -1
- package/dist/actionsStepSummary.js +2 -29
- package/dist/collectNarrativeWhyBullets.d.ts +12 -0
- package/dist/collectNarrativeWhyBullets.d.ts.map +1 -0
- package/dist/collectNarrativeWhyBullets.js +104 -0
- package/dist/deriveScanNarrative.d.ts.map +1 -1
- package/dist/deriveScanNarrative.js +157 -54
- package/dist/deriveScanNarrative.test.js +56 -1
- package/dist/fixtures/repoIntelligenceFixtures.d.ts +2 -0
- package/dist/fixtures/repoIntelligenceFixtures.d.ts.map +1 -1
- package/dist/fixtures/repoIntelligenceFixtures.js +46 -0
- package/dist/formatInsight.d.ts +2 -2
- package/dist/formatInsight.d.ts.map +1 -1
- package/dist/formatInsight.js +2 -7
- package/dist/formatInsight.test.js +1 -1
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -0
- package/dist/narrativeParity.test.d.ts +2 -0
- package/dist/narrativeParity.test.d.ts.map +1 -0
- package/dist/narrativeParity.test.js +64 -0
- package/dist/narrativePresentation.d.ts +50 -0
- package/dist/narrativePresentation.d.ts.map +1 -0
- package/dist/narrativePresentation.js +180 -0
- package/dist/narrativePresentation.test.d.ts +2 -0
- package/dist/narrativePresentation.test.d.ts.map +1 -0
- package/dist/narrativePresentation.test.js +53 -0
- package/dist/normalizeGeneratedText.d.ts +8 -0
- package/dist/normalizeGeneratedText.d.ts.map +1 -0
- package/dist/normalizeGeneratedText.js +31 -0
- package/dist/normalizeGeneratedText.test.d.ts +2 -0
- package/dist/normalizeGeneratedText.test.d.ts.map +1 -0
- package/dist/normalizeGeneratedText.test.js +18 -0
- package/dist/prCheckRunPresentation.d.ts +4 -3
- package/dist/prCheckRunPresentation.d.ts.map +1 -1
- package/dist/prCheckRunPresentation.js +56 -51
- package/dist/prCheckRunPresentation.test.js +2 -2
- package/dist/presentGitHubPrComment.d.ts +9 -0
- package/dist/presentGitHubPrComment.d.ts.map +1 -0
- package/dist/presentGitHubPrComment.js +80 -0
- package/dist/presentScanCardSummary.d.ts.map +1 -1
- package/dist/presentScanCardSummary.js +69 -64
- package/dist/riskVocabulary.js +1 -1
- package/dist/scanCardSummary.d.ts +9 -1
- package/dist/scanCardSummary.d.ts.map +1 -1
- package/dist/scanCardSummary.js +1 -1
- package/dist/scanCardSummary.test.js +12 -8
- package/dist/scanDetailViewModel.d.ts +9 -1
- package/dist/scanDetailViewModel.d.ts.map +1 -1
- package/dist/scanDetailViewModel.js +164 -37
- package/dist/scanDetailViewModel.test.js +27 -1
- package/dist/scanNarrativeFacts.d.ts +21 -8
- package/dist/scanNarrativeFacts.d.ts.map +1 -1
- package/dist/scanNarrativeFacts.js +6 -0
- package/dist/scanSurfaceCopy.d.ts +26 -26
- package/dist/scanSurfaceCopy.d.ts.map +1 -1
- package/dist/scanSurfaceCopy.js +26 -26
- package/package.json +1 -1
|
@@ -2,9 +2,12 @@
|
|
|
2
2
|
* GitHub Check Run markdown — policy → sections → dumb renderer.
|
|
3
3
|
* Thin projection of ScanResult for PR decision support (not a presentation framework).
|
|
4
4
|
*/
|
|
5
|
-
import {
|
|
5
|
+
import { collectWhyBullets } from "./collectNarrativeWhyBullets.js";
|
|
6
|
+
import { deriveScanNarrative } from "./deriveScanNarrative.js";
|
|
6
7
|
import { formatInsight } from "./formatInsight.js";
|
|
7
|
-
import {
|
|
8
|
+
import { normalizeGeneratedText } from "./normalizeGeneratedText.js";
|
|
9
|
+
import { selectReviewerGuidance } from "./narrativePresentation.js";
|
|
10
|
+
import { layerDriverSummary, sortPRInsightsForDisplay, sortRecommendationsForDisplay, truncateWithEllipsis, } from "./actionsStepSummary.js";
|
|
8
11
|
import { mergePostureLabel } from "./riskVocabulary.js";
|
|
9
12
|
import { scanSurfaceCopy } from "./scanSurfaceCopy.js";
|
|
10
13
|
// --- Caps (change only with tests) ---
|
|
@@ -40,43 +43,17 @@ export function formatScanDashboardUrl(webAppOrigin, scanId) {
|
|
|
40
43
|
export function buildPrCheckRunTitle(opts = {}) {
|
|
41
44
|
const base = scanSurfaceCopy.checkRun.titleBase;
|
|
42
45
|
if (opts.baselineOnly) {
|
|
43
|
-
return `${base}
|
|
46
|
+
return `${base} - ${scanSurfaceCopy.checkRun.titleBaselineSuffix}`;
|
|
44
47
|
}
|
|
45
48
|
return base;
|
|
46
49
|
}
|
|
47
|
-
function collectWhyBullets(result, max) {
|
|
48
|
-
const out = [];
|
|
49
|
-
const reasoning = result.decision?.reasoning;
|
|
50
|
-
if (Array.isArray(reasoning)) {
|
|
51
|
-
for (const r of reasoning) {
|
|
52
|
-
const s = humanizeEngineSurfaceText(String(r).trim());
|
|
53
|
-
if (s && !out.includes(s))
|
|
54
|
-
out.push(s);
|
|
55
|
-
if (out.length >= max)
|
|
56
|
-
return out.slice(0, max);
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
const reasons = result.explain?.reasons;
|
|
60
|
-
if (Array.isArray(reasons) && out.length < max) {
|
|
61
|
-
for (const r of reasons) {
|
|
62
|
-
const title = String(r?.title ?? r?.id ?? "").trim();
|
|
63
|
-
const readable = humanizeEngineSurfaceText(title);
|
|
64
|
-
if (readable && !out.includes(readable))
|
|
65
|
-
out.push(readable);
|
|
66
|
-
if (out.length >= max)
|
|
67
|
-
break;
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
if (out.length === 0) {
|
|
71
|
-
const one = deriveScanSummaryText(result);
|
|
72
|
-
if (one)
|
|
73
|
-
out.push(one);
|
|
74
|
-
}
|
|
75
|
-
return out.slice(0, max);
|
|
76
|
-
}
|
|
77
50
|
/** Strong drivers for optional repo-context line (full mode only). */
|
|
78
|
-
export function hasStrongRepoGraphDrivers(result) {
|
|
79
|
-
|
|
51
|
+
export function hasStrongRepoGraphDrivers(result, facts) {
|
|
52
|
+
if (facts?.availability.mode === "pr_intelligence" ||
|
|
53
|
+
facts?.availability.tiersPresent.tier1) {
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
56
|
+
const phrases = collectWhyBullets(facts ?? deriveScanNarrative(result), result, CHECK_RUN_MAX_REPO_DRIVER_PHRASES);
|
|
80
57
|
return phrases.some((p) => p.trim().length >= 12);
|
|
81
58
|
}
|
|
82
59
|
function hasActionableBullets(result) {
|
|
@@ -92,7 +69,7 @@ function insightToBullet(insight) {
|
|
|
92
69
|
const msg = truncateWithEllipsis(f.message, CHECK_RUN_ACTION_BULLET_MAX_CHARS);
|
|
93
70
|
const action = f.action.trim();
|
|
94
71
|
if (action && action.length < 120) {
|
|
95
|
-
return `${msg}
|
|
72
|
+
return normalizeGeneratedText(`${msg} - ${truncateWithEllipsis(action, 100)}`);
|
|
96
73
|
}
|
|
97
74
|
return msg;
|
|
98
75
|
}
|
|
@@ -100,7 +77,7 @@ function recommendationToBullet(rec) {
|
|
|
100
77
|
const title = String(rec.title ?? "").trim();
|
|
101
78
|
const rat = String(rec.rationale ?? "").trim();
|
|
102
79
|
const pkgs = Array.isArray(rec.packages) && rec.packages.length > 0
|
|
103
|
-
? ` (${rec.packages.slice(0, 3).join(", ")}${rec.packages.length > 3 ? ",
|
|
80
|
+
? ` (${rec.packages.slice(0, 3).join(", ")}${rec.packages.length > 3 ? ", ..." : ""})`
|
|
104
81
|
: "";
|
|
105
82
|
if (rat && (!title || rat.length > title.length)) {
|
|
106
83
|
return truncateWithEllipsis(rat, CHECK_RUN_ACTION_BULLET_MAX_CHARS) + pkgs;
|
|
@@ -113,6 +90,31 @@ function findingToBullet(f) {
|
|
|
113
90
|
const pkg = f.packageName ? ` (\`${f.packageName}\`)` : "";
|
|
114
91
|
return (truncateWithEllipsis(title || f.description, CHECK_RUN_ACTION_BULLET_MAX_CHARS) + pkg);
|
|
115
92
|
}
|
|
93
|
+
function guidanceToActionBullet(g) {
|
|
94
|
+
const msg = truncateWithEllipsis(g.message.trim(), CHECK_RUN_ACTION_BULLET_MAX_CHARS);
|
|
95
|
+
const action = g.remediation?.trim();
|
|
96
|
+
if (action && action.length < 120) {
|
|
97
|
+
return normalizeGeneratedText(`${msg} - ${truncateWithEllipsis(action, 100)}`);
|
|
98
|
+
}
|
|
99
|
+
return normalizeGeneratedText(msg);
|
|
100
|
+
}
|
|
101
|
+
function buildActionBulletsFromFacts(facts, result, max) {
|
|
102
|
+
const prIntel = facts.availability.mode === "pr_intelligence" ||
|
|
103
|
+
facts.availability.tiersPresent.tier1;
|
|
104
|
+
if (!prIntel) {
|
|
105
|
+
return buildActionBullets(result, max);
|
|
106
|
+
}
|
|
107
|
+
const out = [];
|
|
108
|
+
for (const g of selectReviewerGuidance(facts, { scope: "changed", max })) {
|
|
109
|
+
out.push(guidanceToActionBullet(g));
|
|
110
|
+
if (out.length >= max)
|
|
111
|
+
return out.slice(0, max);
|
|
112
|
+
}
|
|
113
|
+
if (out.length >= max)
|
|
114
|
+
return out.slice(0, max);
|
|
115
|
+
const legacy = buildActionBullets(result, max - out.length);
|
|
116
|
+
return [...out, ...legacy].slice(0, max);
|
|
117
|
+
}
|
|
116
118
|
function buildActionBullets(result, max) {
|
|
117
119
|
const out = [];
|
|
118
120
|
const sortedI = sortPRInsightsForDisplay(Array.isArray(result.insights) ? result.insights : []);
|
|
@@ -156,12 +158,13 @@ function layerScoreRows(result) {
|
|
|
156
158
|
}
|
|
157
159
|
return rows;
|
|
158
160
|
}
|
|
159
|
-
export function deriveCheckRunPolicy(result, ctx) {
|
|
161
|
+
export function deriveCheckRunPolicy(result, ctx, facts) {
|
|
162
|
+
const resolvedFacts = facts ?? deriveScanNarrative(result);
|
|
160
163
|
const baseline = ctx.baseline;
|
|
161
|
-
const actionBullets =
|
|
164
|
+
const actionBullets = buildActionBulletsFromFacts(resolvedFacts, result, CHECK_RUN_MAX_ACTION_BULLETS);
|
|
162
165
|
const layerRows = layerScoreRows(result);
|
|
163
166
|
const showRepoGraphContext = !baseline &&
|
|
164
|
-
hasStrongRepoGraphDrivers(result) &&
|
|
167
|
+
hasStrongRepoGraphDrivers(result, resolvedFacts) &&
|
|
165
168
|
typeof result.totalScore === "number" &&
|
|
166
169
|
Number.isFinite(result.totalScore);
|
|
167
170
|
const showLayerScores = !baseline && layerRows.length > 0;
|
|
@@ -189,14 +192,15 @@ function buildLeadSection(result, policy) {
|
|
|
189
192
|
: null;
|
|
190
193
|
return { kind: "lead", posture, riskIndexLine };
|
|
191
194
|
}
|
|
192
|
-
export function buildPrCheckRunSections(policy, result, ctx) {
|
|
195
|
+
export function buildPrCheckRunSections(policy, result, ctx, facts) {
|
|
196
|
+
const resolvedFacts = facts ?? deriveScanNarrative(result);
|
|
193
197
|
const sections = {};
|
|
194
198
|
sections.lead = buildLeadSection(result, policy);
|
|
195
|
-
const why = collectWhyBullets(result, policy.maxWhyBullets);
|
|
199
|
+
const why = collectWhyBullets(resolvedFacts, result, policy.maxWhyBullets);
|
|
196
200
|
if (why.length > 0) {
|
|
197
201
|
sections.why = { kind: "why", bullets: why };
|
|
198
202
|
}
|
|
199
|
-
const actions =
|
|
203
|
+
const actions = buildActionBulletsFromFacts(resolvedFacts, result, policy.maxActionBullets);
|
|
200
204
|
if (actions.length > 0) {
|
|
201
205
|
sections.actions = { kind: "actions", bullets: actions };
|
|
202
206
|
}
|
|
@@ -212,7 +216,7 @@ export function buildPrCheckRunSections(policy, result, ctx) {
|
|
|
212
216
|
sections.repoContext = {
|
|
213
217
|
kind: "repoContext",
|
|
214
218
|
score,
|
|
215
|
-
driverPhrases: collectWhyBullets(result, policy.maxRepoDriverPhrases),
|
|
219
|
+
driverPhrases: collectWhyBullets(resolvedFacts, result, policy.maxRepoDriverPhrases),
|
|
216
220
|
};
|
|
217
221
|
}
|
|
218
222
|
if (policy.showLayerScores) {
|
|
@@ -270,8 +274,8 @@ export function renderCheckRunMarkdown(sections) {
|
|
|
270
274
|
break;
|
|
271
275
|
}
|
|
272
276
|
case "repoContext": {
|
|
273
|
-
const drivers = section.driverPhrases.join("
|
|
274
|
-
parts.push(`${scanSurfaceCopy.checkRun.repoContextLabel} ${section.score}/100
|
|
277
|
+
const drivers = section.driverPhrases.join(" | ");
|
|
278
|
+
parts.push(normalizeGeneratedText(`${scanSurfaceCopy.checkRun.repoContextLabel} ${section.score}/100 - ${drivers}`));
|
|
275
279
|
parts.push("");
|
|
276
280
|
break;
|
|
277
281
|
}
|
|
@@ -280,7 +284,7 @@ export function renderCheckRunMarkdown(sections) {
|
|
|
280
284
|
parts.push(`<summary>${scanSurfaceCopy.checkRun.layerScoresDetailsSummary}</summary>`);
|
|
281
285
|
parts.push("");
|
|
282
286
|
for (const row of section.rows) {
|
|
283
|
-
parts.push(`- **${row.label}** ${row.score}/100
|
|
287
|
+
parts.push(normalizeGeneratedText(`- **${row.label}** ${row.score}/100 - ${row.driver}`));
|
|
284
288
|
}
|
|
285
289
|
parts.push("");
|
|
286
290
|
parts.push("</details>");
|
|
@@ -297,15 +301,16 @@ export function renderCheckRunMarkdown(sections) {
|
|
|
297
301
|
}
|
|
298
302
|
}
|
|
299
303
|
}
|
|
300
|
-
let md = parts.join("\n").trimEnd();
|
|
304
|
+
let md = normalizeGeneratedText(parts.join("\n").trimEnd());
|
|
301
305
|
if (md.length > CHECK_RUN_SOFT_MAX_CHARS) {
|
|
302
|
-
md = md.slice(0, CHECK_RUN_SOFT_MAX_CHARS - 1) + "
|
|
306
|
+
md = md.slice(0, CHECK_RUN_SOFT_MAX_CHARS - 1) + "...";
|
|
303
307
|
}
|
|
304
308
|
return md;
|
|
305
309
|
}
|
|
306
310
|
export function buildPrCheckRunSummaryMarkdown(ctx) {
|
|
307
|
-
const
|
|
308
|
-
const
|
|
311
|
+
const facts = deriveScanNarrative(ctx.result);
|
|
312
|
+
const policy = deriveCheckRunPolicy(ctx.result, { baseline: ctx.baseline }, facts);
|
|
313
|
+
const sections = buildPrCheckRunSections(policy, ctx.result, ctx, facts);
|
|
309
314
|
return renderCheckRunMarkdown(sections);
|
|
310
315
|
}
|
|
311
316
|
/** Whether baseline scan has no actionable PR bullets (for tests / callers). */
|
|
@@ -38,7 +38,7 @@ describe("buildPrCheckRunTitle", () => {
|
|
|
38
38
|
expect(buildPrCheckRunTitle()).not.toContain("—");
|
|
39
39
|
});
|
|
40
40
|
it("appends baseline suffix when requested", () => {
|
|
41
|
-
expect(buildPrCheckRunTitle({ baselineOnly: true })).toBe("PR dependency change
|
|
41
|
+
expect(buildPrCheckRunTitle({ baselineOnly: true })).toBe("PR dependency change - baseline scan only");
|
|
42
42
|
});
|
|
43
43
|
});
|
|
44
44
|
describe("formatScanDashboardUrl", () => {
|
|
@@ -271,7 +271,7 @@ describe("buildPrCheckRunSummaryMarkdown", () => {
|
|
|
271
271
|
baseline: false,
|
|
272
272
|
});
|
|
273
273
|
if (md.includes("Layer scores")) {
|
|
274
|
-
expect(md).toMatch(/Maintainability.*\/100
|
|
274
|
+
expect(md).toMatch(/Maintainability.*\/100 -/);
|
|
275
275
|
expect(md).not.toMatch(/\| Security \| 0 \|/);
|
|
276
276
|
}
|
|
277
277
|
});
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { ScanNarrativeFacts } from "./scanNarrativeFacts.js";
|
|
2
|
+
import type { PRDecision, PRInsight, ScanResult } from "./types.js";
|
|
3
|
+
/**
|
|
4
|
+
* PR comment markdown from narrative facts (compressed dashboard story).
|
|
5
|
+
*/
|
|
6
|
+
export declare function presentGitHubPrComment(facts: ScanNarrativeFacts, result: ScanResult): string;
|
|
7
|
+
/** Backward-compatible entry: derives facts then presents. */
|
|
8
|
+
export declare function renderInsightsAsMarkdown(insights: PRInsight[], decision: PRDecision): string;
|
|
9
|
+
//# sourceMappingURL=presentGitHubPrComment.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"presentGitHubPrComment.d.ts","sourceRoot":"","sources":["../src/presentGitHubPrComment.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAClE,OAAO,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAoBpE;;GAEG;AACH,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,kBAAkB,EACzB,MAAM,EAAE,UAAU,GACjB,MAAM,CA6CR;AAED,8DAA8D;AAC9D,wBAAgB,wBAAwB,CACtC,QAAQ,EAAE,SAAS,EAAE,EACrB,QAAQ,EAAE,UAAU,GACnB,MAAM,CAgBR"}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { deriveScanNarrative } from "./deriveScanNarrative.js";
|
|
2
|
+
import { composeVerificationPrompt, formatChangedPackagesShort, formatUsageSummaryLine, selectReviewerGuidance, } from "./narrativePresentation.js";
|
|
3
|
+
import { normalizeGeneratedText } from "./normalizeGeneratedText.js";
|
|
4
|
+
import { MERGE_POSTURE_LABEL, mergePostureFromDecision, } from "./riskVocabulary.js";
|
|
5
|
+
import { scanSurfaceCopy } from "./scanSurfaceCopy.js";
|
|
6
|
+
function renderGuidanceBlock(message, where, action) {
|
|
7
|
+
return [
|
|
8
|
+
normalizeGeneratedText(message),
|
|
9
|
+
"",
|
|
10
|
+
"**Where it shows up**",
|
|
11
|
+
"",
|
|
12
|
+
normalizeGeneratedText(where),
|
|
13
|
+
"",
|
|
14
|
+
"**What to do**",
|
|
15
|
+
"",
|
|
16
|
+
normalizeGeneratedText(action),
|
|
17
|
+
].join("\n");
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* PR comment markdown from narrative facts (compressed dashboard story).
|
|
21
|
+
*/
|
|
22
|
+
export function presentGitHubPrComment(facts, result) {
|
|
23
|
+
const posture = facts.mergePosture ??
|
|
24
|
+
mergePostureFromDecision(result.decision?.recommendation);
|
|
25
|
+
const title = posture
|
|
26
|
+
? `**${MERGE_POSTURE_LABEL[posture]}**`
|
|
27
|
+
: `**${scanSurfaceCopy.checkRun.mergePostureUnavailable}**`;
|
|
28
|
+
const introLines = [];
|
|
29
|
+
const changed = formatChangedPackagesShort(facts, 3);
|
|
30
|
+
if (changed)
|
|
31
|
+
introLines.push(`Changed: ${changed}`);
|
|
32
|
+
const usage = formatUsageSummaryLine(facts, 1);
|
|
33
|
+
if (usage)
|
|
34
|
+
introLines.push(usage);
|
|
35
|
+
const verify = composeVerificationPrompt(facts);
|
|
36
|
+
if (verify)
|
|
37
|
+
introLines.push(`Verify: ${verify}`);
|
|
38
|
+
const guidance = selectReviewerGuidance(facts, { scope: "changed", max: 3 });
|
|
39
|
+
if (guidance.length === 0) {
|
|
40
|
+
const fallback = selectReviewerGuidance(facts, { max: 3 });
|
|
41
|
+
guidance.push(...fallback.slice(0, 3 - guidance.length));
|
|
42
|
+
}
|
|
43
|
+
const blocks = guidance.map((g) => {
|
|
44
|
+
const where = g.context?.trim() ||
|
|
45
|
+
facts.packageUsage
|
|
46
|
+
.flatMap((u) => u.paths.slice(0, 1))
|
|
47
|
+
.filter(Boolean)[0] ||
|
|
48
|
+
"See scan detail for affected paths.";
|
|
49
|
+
const action = g.remediation?.trim() ||
|
|
50
|
+
composeVerificationPrompt(facts) ||
|
|
51
|
+
"Review before merge.";
|
|
52
|
+
return renderGuidanceBlock(g.message, where, action);
|
|
53
|
+
});
|
|
54
|
+
const parts = [title];
|
|
55
|
+
if (introLines.length > 0) {
|
|
56
|
+
parts.push("", introLines.join("\n"));
|
|
57
|
+
}
|
|
58
|
+
if (blocks.length > 0) {
|
|
59
|
+
parts.push("", ...blocks);
|
|
60
|
+
}
|
|
61
|
+
return parts.join("\n\n---\n\n").trimEnd();
|
|
62
|
+
}
|
|
63
|
+
/** Backward-compatible entry: derives facts then presents. */
|
|
64
|
+
export function renderInsightsAsMarkdown(insights, decision) {
|
|
65
|
+
const result = {
|
|
66
|
+
totalScore: 0,
|
|
67
|
+
layerScores: {
|
|
68
|
+
security: 0,
|
|
69
|
+
maintainability: 0,
|
|
70
|
+
ecosystem: 0,
|
|
71
|
+
upgradeImpact: 0,
|
|
72
|
+
},
|
|
73
|
+
findings: [],
|
|
74
|
+
generatedAt: new Date().toISOString(),
|
|
75
|
+
insights,
|
|
76
|
+
decision,
|
|
77
|
+
};
|
|
78
|
+
const facts = deriveScanNarrative(result);
|
|
79
|
+
return presentGitHubPrComment(facts, result);
|
|
80
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"presentScanCardSummary.d.ts","sourceRoot":"","sources":["../src/presentScanCardSummary.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"presentScanCardSummary.d.ts","sourceRoot":"","sources":["../src/presentScanCardSummary.ts"],"names":[],"mappings":"AAKA,OAAO,EAKL,KAAK,eAAe,EACpB,KAAK,kBAAkB,EACxB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAClE,OAAO,EAEL,KAAK,mBAAmB,EACzB,MAAM,gCAAgC,CAAC;AAkBxC,OAAO,EAAuB,KAAK,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAE7E,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE7C,MAAM,MAAM,6BAA6B,GAAG;IAC1C,cAAc,CAAC,EAAE,kBAAkB,CAAC;IACpC,QAAQ,CAAC,EAAE,UAAU,CAAC,UAAU,CAAC,CAAC;CACnC,CAAC;AA2HF;;GAEG;AACH,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,kBAAkB,EACzB,OAAO,GAAE,6BAAkC,GAC1C,eAAe,CA8HjB;AAED,YAAY,EAAE,mBAAmB,EAAE,YAAY,EAAE,CAAC;AAElD,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,kBAAkB,GACxB,mBAAmB,GAAG,IAAI,CAE5B"}
|
|
@@ -1,35 +1,11 @@
|
|
|
1
|
-
import { phraseForFamily, } from "./cardObservationCatalog.js";
|
|
2
|
-
import { aggregateFindingCounts, deriveRiskIndexBand, } from "./scanCardSummary.js";
|
|
1
|
+
import { isCatalogPhrase, phraseForFamily, } from "./cardObservationCatalog.js";
|
|
2
|
+
import { aggregateFindingCounts, deriveRiskIndexBand, SCAN_CARD_SCANNING_SUMMARY, } from "./scanCardSummary.js";
|
|
3
3
|
import { deriveCardExposureDisplay, } from "./formatCardExposureDisplay.js";
|
|
4
4
|
import { formatCardAreaLabels } from "./formatCardAreaLabels.js";
|
|
5
|
+
import { composeContextLineFromFacts, composeVerificationPrompt, formatBlastRadiusDetailLine, formatChangedPackagesShort, formatFrameworksSummary, formatUsageSummaryLine, labelBlastRadiusLevel, labelReachabilityKind, labelRuntimeSurface, } from "./narrativePresentation.js";
|
|
6
|
+
import { normalizeGeneratedText, normalizeGeneratedTextNullable, } from "./normalizeGeneratedText.js";
|
|
5
7
|
import { MERGE_POSTURE_LABEL } from "./riskVocabulary.js";
|
|
6
8
|
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
9
|
function formatAffectedAreaLabels(facts) {
|
|
34
10
|
const ordered = [];
|
|
35
11
|
for (const area of facts.affectedAreas) {
|
|
@@ -62,7 +38,7 @@ function selectSecondaryLines(facts, exclude) {
|
|
|
62
38
|
}
|
|
63
39
|
return lines;
|
|
64
40
|
}
|
|
65
|
-
function repositoryContextPhrases(facts) {
|
|
41
|
+
function repositoryContextPhrases(facts, max) {
|
|
66
42
|
const phrases = [];
|
|
67
43
|
const seen = new Set();
|
|
68
44
|
for (const ctx of facts.repositoryContext) {
|
|
@@ -71,32 +47,13 @@ function repositoryContextPhrases(facts) {
|
|
|
71
47
|
continue;
|
|
72
48
|
seen.add(phrase);
|
|
73
49
|
phrases.push(phrase);
|
|
74
|
-
if (phrases.length >=
|
|
50
|
+
if (phrases.length >= max)
|
|
75
51
|
break;
|
|
76
52
|
}
|
|
77
53
|
return phrases;
|
|
78
54
|
}
|
|
79
|
-
function
|
|
80
|
-
const
|
|
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);
|
|
55
|
+
function buildLegacyObservations(facts, primaryInsight, repoPhraseCap) {
|
|
56
|
+
const repoPhrases = repositoryContextPhrases(facts, repoPhraseCap);
|
|
100
57
|
const secondary = selectSecondaryLines(facts, primaryInsight);
|
|
101
58
|
if (primaryInsight) {
|
|
102
59
|
return {
|
|
@@ -110,10 +67,34 @@ function buildLegacyObservations(facts, primaryInsight) {
|
|
|
110
67
|
return { operationalObservations: [], supportingLine: null };
|
|
111
68
|
}
|
|
112
69
|
return {
|
|
113
|
-
operationalObservations: repoPhrases.slice(0,
|
|
70
|
+
operationalObservations: repoPhrases.slice(0, repoPhraseCap),
|
|
114
71
|
supportingLine: repoPhrases.length === 1 ? (secondary[0] ?? null) : null,
|
|
115
72
|
};
|
|
116
73
|
}
|
|
74
|
+
function normalizeCardSummary(summary) {
|
|
75
|
+
return {
|
|
76
|
+
...summary,
|
|
77
|
+
headline: normalizeGeneratedText(summary.headline),
|
|
78
|
+
summaryLine: normalizeGeneratedTextNullable(summary.summaryLine),
|
|
79
|
+
supportingLine: normalizeGeneratedTextNullable(summary.supportingLine),
|
|
80
|
+
changedPackagesDisplay: normalizeGeneratedTextNullable(summary.changedPackagesDisplay),
|
|
81
|
+
runtimeSurfaceLabel: normalizeGeneratedTextNullable(summary.runtimeSurfaceLabel),
|
|
82
|
+
reachabilityLabel: normalizeGeneratedTextNullable(summary.reachabilityLabel),
|
|
83
|
+
blastRadiusLabel: normalizeGeneratedTextNullable(summary.blastRadiusLabel),
|
|
84
|
+
primaryInsight: normalizeGeneratedTextNullable(summary.primaryInsight),
|
|
85
|
+
structuralOnlyDisclaimer: normalizeGeneratedTextNullable(summary.structuralOnlyDisclaimer),
|
|
86
|
+
usageSummary: normalizeGeneratedTextNullable(summary.usageSummary),
|
|
87
|
+
verificationLine: normalizeGeneratedTextNullable(summary.verificationLine),
|
|
88
|
+
blastRadiusDetail: normalizeGeneratedTextNullable(summary.blastRadiusDetail),
|
|
89
|
+
frameworksSummary: normalizeGeneratedTextNullable(summary.frameworksSummary),
|
|
90
|
+
affectedAreas: summary.affectedAreas.map((a) => normalizeGeneratedText(a)),
|
|
91
|
+
topAffectedAreas: summary.topAffectedAreas.map((a) => normalizeGeneratedText(a)),
|
|
92
|
+
operationalObservations: summary.operationalObservations.map((p) => {
|
|
93
|
+
const normalized = normalizeGeneratedText(p);
|
|
94
|
+
return isCatalogPhrase(normalized) ? normalized : p;
|
|
95
|
+
}),
|
|
96
|
+
};
|
|
97
|
+
}
|
|
117
98
|
/**
|
|
118
99
|
* Dashboard card presentation DTO from consumer-agnostic facts.
|
|
119
100
|
*/
|
|
@@ -129,23 +110,27 @@ export function presentScanCardSummary(facts, options = {}) {
|
|
|
129
110
|
affectedAreas: [],
|
|
130
111
|
primaryInsight: null,
|
|
131
112
|
structuralOnlyDisclaimer: null,
|
|
113
|
+
usageSummary: null,
|
|
114
|
+
verificationLine: null,
|
|
115
|
+
blastRadiusDetail: null,
|
|
116
|
+
frameworksSummary: null,
|
|
132
117
|
};
|
|
133
118
|
if (pipelineStatus === "queued" || pipelineStatus === "running") {
|
|
134
|
-
return {
|
|
119
|
+
return normalizeCardSummary({
|
|
135
120
|
mergePosture: null,
|
|
136
121
|
riskIndex: null,
|
|
137
122
|
riskIndexBand: null,
|
|
138
123
|
headline: scanSurfaceCopy.pipeline.scanRunning,
|
|
139
|
-
summaryLine:
|
|
124
|
+
summaryLine: SCAN_CARD_SCANNING_SUMMARY,
|
|
140
125
|
findingCounts: null,
|
|
141
126
|
topAffectedAreas: [],
|
|
142
127
|
operationalObservations: [],
|
|
143
128
|
supportingLine: null,
|
|
144
129
|
...emptyPresentationFields,
|
|
145
|
-
};
|
|
130
|
+
});
|
|
146
131
|
}
|
|
147
132
|
if (pipelineStatus === "failed") {
|
|
148
|
-
return {
|
|
133
|
+
return normalizeCardSummary({
|
|
149
134
|
mergePosture: null,
|
|
150
135
|
riskIndex: null,
|
|
151
136
|
riskIndexBand: null,
|
|
@@ -156,7 +141,7 @@ export function presentScanCardSummary(facts, options = {}) {
|
|
|
156
141
|
operationalObservations: [],
|
|
157
142
|
supportingLine: null,
|
|
158
143
|
...emptyPresentationFields,
|
|
159
|
-
};
|
|
144
|
+
});
|
|
160
145
|
}
|
|
161
146
|
const posture = facts.mergePosture;
|
|
162
147
|
const riskIndex = facts.riskIndex;
|
|
@@ -167,12 +152,17 @@ export function presentScanCardSummary(facts, options = {}) {
|
|
|
167
152
|
const findingCounts = options.findings
|
|
168
153
|
? aggregateFindingCounts(options.findings)
|
|
169
154
|
: null;
|
|
170
|
-
const
|
|
155
|
+
const prIntelligence = facts.availability.mode === "pr_intelligence" ||
|
|
156
|
+
facts.availability.tiersPresent.tier1;
|
|
157
|
+
const changedPackagesDisplay = formatChangedPackagesShort(facts, 2);
|
|
171
158
|
const runtimeSurfaceLabel = labelRuntimeSurface(facts);
|
|
172
|
-
const reachabilityLabel =
|
|
173
|
-
const blastRadiusLabel =
|
|
159
|
+
const reachabilityLabel = labelReachabilityKind(facts);
|
|
160
|
+
const blastRadiusLabel = labelBlastRadiusLevel(facts);
|
|
174
161
|
const affectedAreas = formatAffectedAreaLabels(facts);
|
|
175
|
-
const contextLine =
|
|
162
|
+
const contextLine = composeContextLineFromFacts(facts, {
|
|
163
|
+
includePathSample: prIntelligence,
|
|
164
|
+
maxAreas: 2,
|
|
165
|
+
});
|
|
176
166
|
const structuralOnlyDisclaimer = facts.availability.mode === "graph_fallback" &&
|
|
177
167
|
!facts.availability.tiersPresent.tier1
|
|
178
168
|
? scanSurfaceCopy.narrativeCard.structuralOnlyDisclaimer
|
|
@@ -180,8 +170,19 @@ export function presentScanCardSummary(facts, options = {}) {
|
|
|
180
170
|
const insightMessage = selectPrimaryInsight(facts);
|
|
181
171
|
const primaryInsight = insightMessage ??
|
|
182
172
|
(facts.availability.mode !== "graph_fallback" ? contextLine : null);
|
|
183
|
-
const
|
|
184
|
-
|
|
173
|
+
const usageSummary = prIntelligence ? formatUsageSummaryLine(facts, 1) : null;
|
|
174
|
+
const verificationLine = prIntelligence
|
|
175
|
+
? composeVerificationPrompt(facts)
|
|
176
|
+
: null;
|
|
177
|
+
const blastRadiusDetail = prIntelligence
|
|
178
|
+
? formatBlastRadiusDetailLine(facts, 1)
|
|
179
|
+
: null;
|
|
180
|
+
const frameworksSummary = prIntelligence
|
|
181
|
+
? formatFrameworksSummary(facts, 2)
|
|
182
|
+
: null;
|
|
183
|
+
const repoPhraseCap = prIntelligence ? 0 : 3;
|
|
184
|
+
const { operationalObservations, supportingLine } = buildLegacyObservations(facts, primaryInsight, repoPhraseCap);
|
|
185
|
+
return normalizeCardSummary({
|
|
185
186
|
mergePosture: posture,
|
|
186
187
|
riskIndex,
|
|
187
188
|
riskIndexBand,
|
|
@@ -200,7 +201,11 @@ export function presentScanCardSummary(facts, options = {}) {
|
|
|
200
201
|
affectedAreas,
|
|
201
202
|
primaryInsight,
|
|
202
203
|
structuralOnlyDisclaimer,
|
|
203
|
-
|
|
204
|
+
usageSummary,
|
|
205
|
+
verificationLine,
|
|
206
|
+
blastRadiusDetail,
|
|
207
|
+
frameworksSummary,
|
|
208
|
+
});
|
|
204
209
|
}
|
|
205
210
|
export function exposureFromFacts(facts) {
|
|
206
211
|
return deriveCardExposureDisplay(facts.riskIndex) ?? null;
|
package/dist/riskVocabulary.js
CHANGED
|
@@ -34,7 +34,7 @@ export function mergePostureFromDecision(decision) {
|
|
|
34
34
|
return null;
|
|
35
35
|
}
|
|
36
36
|
/** Returns the display label for a decision, or a fallback string. */
|
|
37
|
-
export function mergePostureLabel(decision, fallback = "
|
|
37
|
+
export function mergePostureLabel(decision, fallback = "-") {
|
|
38
38
|
const posture = mergePostureFromDecision(decision);
|
|
39
39
|
return posture ? MERGE_POSTURE_LABEL[posture] : fallback;
|
|
40
40
|
}
|
|
@@ -34,8 +34,16 @@ export type ScanCardSummary = {
|
|
|
34
34
|
affectedAreas: string[];
|
|
35
35
|
primaryInsight: string | null;
|
|
36
36
|
structuralOnlyDisclaimer: string | null;
|
|
37
|
+
/** One-line usage hint from packageUsage paths or areas. */
|
|
38
|
+
usageSummary: string | null;
|
|
39
|
+
/** Single verification prompt from changed-scope guidance or usage. */
|
|
40
|
+
verificationLine: string | null;
|
|
41
|
+
/** Optional blast factor subline when factors exist. */
|
|
42
|
+
blastRadiusDetail: string | null;
|
|
43
|
+
/** Short framework list (max 2 on card). */
|
|
44
|
+
frameworksSummary: string | null;
|
|
37
45
|
};
|
|
38
|
-
export declare const SCAN_CARD_SCANNING_SUMMARY = "Waiting for results
|
|
46
|
+
export declare const SCAN_CARD_SCANNING_SUMMARY = "Waiting for results...";
|
|
39
47
|
export type PipelineCompletionEvidence = {
|
|
40
48
|
scannedAt?: string | null;
|
|
41
49
|
decision?: string | null;
|
|
@@ -1 +1 @@
|
|
|
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;
|
|
1
|
+
{"version":3,"file":"scanCardSummary.d.ts","sourceRoot":"","sources":["../src/scanCardSummary.ts"],"names":[],"mappings":"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"}
|
package/dist/scanCardSummary.js
CHANGED
|
@@ -3,7 +3,7 @@ import { presentScanCardSummary } from "./presentScanCardSummary.js";
|
|
|
3
3
|
import { mergePostureFromDecision, } from "./riskVocabulary.js";
|
|
4
4
|
import { scanSurfaceCopy } from "./scanSurfaceCopy.js";
|
|
5
5
|
const STALE_SUBLINE = "Based on earlier commit";
|
|
6
|
-
export const SCAN_CARD_SCANNING_SUMMARY = "Waiting for results
|
|
6
|
+
export const SCAN_CARD_SCANNING_SUMMARY = "Waiting for results...";
|
|
7
7
|
function normalizePipelineStatus(status) {
|
|
8
8
|
const st = String(status ?? "")
|
|
9
9
|
.trim()
|
|
@@ -11,6 +11,10 @@ const pipelinePresentationDefaults = {
|
|
|
11
11
|
affectedAreas: [],
|
|
12
12
|
primaryInsight: null,
|
|
13
13
|
structuralOnlyDisclaimer: null,
|
|
14
|
+
usageSummary: null,
|
|
15
|
+
verificationLine: null,
|
|
16
|
+
blastRadiusDetail: null,
|
|
17
|
+
frameworksSummary: null,
|
|
14
18
|
};
|
|
15
19
|
const baseResult = {
|
|
16
20
|
totalScore: 10,
|
|
@@ -64,7 +68,7 @@ describe("deriveScanCardSummary", () => {
|
|
|
64
68
|
it("returns scanning copy for queued/running", () => {
|
|
65
69
|
const queued = deriveScanCardSummary(null, "queued");
|
|
66
70
|
expect(queued.headline).toBe("Scan in progress");
|
|
67
|
-
expect(queued.summaryLine).toBe("Waiting for results
|
|
71
|
+
expect(queued.summaryLine).toBe("Waiting for results...");
|
|
68
72
|
expect(queued.mergePosture).toBeNull();
|
|
69
73
|
const running = deriveScanCardSummary(null, "running");
|
|
70
74
|
expect(running.headline).toBe("Scan in progress");
|
|
@@ -184,7 +188,7 @@ describe("isPipelineCardSummary", () => {
|
|
|
184
188
|
riskIndex: null,
|
|
185
189
|
riskIndexBand: null,
|
|
186
190
|
headline: "Scan in progress",
|
|
187
|
-
summaryLine: "Waiting for results
|
|
191
|
+
summaryLine: "Waiting for results...",
|
|
188
192
|
findingCounts: null,
|
|
189
193
|
topAffectedAreas: [],
|
|
190
194
|
operationalObservations: [],
|
|
@@ -198,7 +202,7 @@ describe("isPipelineCardSummary", () => {
|
|
|
198
202
|
riskIndex: 72,
|
|
199
203
|
riskIndexBand: "high",
|
|
200
204
|
headline: "Risky",
|
|
201
|
-
summaryLine: "Waiting for results
|
|
205
|
+
summaryLine: "Waiting for results...",
|
|
202
206
|
findingCounts: null,
|
|
203
207
|
topAffectedAreas: [],
|
|
204
208
|
operationalObservations: [],
|
|
@@ -209,7 +213,7 @@ describe("isPipelineCardSummary", () => {
|
|
|
209
213
|
});
|
|
210
214
|
describe("isPipelinePlaceholderCopy", () => {
|
|
211
215
|
it("identifies waiting copy", () => {
|
|
212
|
-
expect(isPipelinePlaceholderCopy("Waiting for results
|
|
216
|
+
expect(isPipelinePlaceholderCopy("Waiting for results...")).toBe(true);
|
|
213
217
|
expect(isPipelinePlaceholderCopy("Auth change")).toBe(false);
|
|
214
218
|
});
|
|
215
219
|
});
|
|
@@ -223,9 +227,9 @@ describe("deriveScanCardSummaryFromDenormalized", () => {
|
|
|
223
227
|
expect(summary.operationalObservations).toEqual([]);
|
|
224
228
|
});
|
|
225
229
|
it("does not inject pipeline placeholder summaryText", () => {
|
|
226
|
-
const summary = deriveScanCardSummaryFromDenormalized("risky", 72, "Waiting for results
|
|
230
|
+
const summary = deriveScanCardSummaryFromDenormalized("risky", 72, "Waiting for results...", "done");
|
|
227
231
|
expect(summary.mergePosture).toBe("risky");
|
|
228
|
-
expect(summary.summaryLine).not.toBe("Waiting for results
|
|
232
|
+
expect(summary.summaryLine).not.toBe("Waiting for results...");
|
|
229
233
|
});
|
|
230
234
|
it("does not inject raw generic summaryText on quiet safe cards", () => {
|
|
231
235
|
const summary = deriveScanCardSummaryFromDenormalized("safe", 12, "No high-confidence merge risks from this PR dependency change", "done");
|
|
@@ -239,11 +243,11 @@ describe("resolvePrScanCardSummary", () => {
|
|
|
239
243
|
pipelineStatus: "running",
|
|
240
244
|
decision: "risky",
|
|
241
245
|
totalScore: 80,
|
|
242
|
-
summaryText: "Waiting for results
|
|
246
|
+
summaryText: "Waiting for results...",
|
|
243
247
|
result: null,
|
|
244
248
|
});
|
|
245
249
|
expect(summary.mergePosture).toBe("risky");
|
|
246
250
|
expect(summary.headline).toBe("Risky");
|
|
247
|
-
expect(summary.summaryLine).not.toBe("Waiting for results
|
|
251
|
+
expect(summary.summaryLine).not.toBe("Waiting for results...");
|
|
248
252
|
});
|
|
249
253
|
});
|