@mergesignal/shared 0.4.3 → 0.6.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.
- package/dist/actionsStepSummary.d.ts +1 -22
- package/dist/actionsStepSummary.d.ts.map +1 -1
- package/dist/actionsStepSummary.js +19 -716
- package/dist/actionsStepSummary.test.js +34 -329
- package/dist/assessmentLabels.d.ts +6 -0
- package/dist/assessmentLabels.d.ts.map +1 -0
- package/dist/assessmentLabels.js +33 -0
- package/dist/assessmentProjection.d.ts +12 -0
- package/dist/assessmentProjection.d.ts.map +1 -0
- package/dist/assessmentProjection.js +100 -0
- package/dist/assessmentSchema.d.ts +155 -0
- package/dist/assessmentSchema.d.ts.map +1 -0
- package/dist/assessmentSchema.js +110 -0
- package/dist/cardObservationCatalog.d.ts +2 -0
- package/dist/cardObservationCatalog.d.ts.map +1 -1
- package/dist/cardObservationCatalog.js +47 -1
- package/dist/engineWireRegression.test.js +22 -2
- package/dist/fixtures/assessmentFixtures.d.ts +13 -0
- package/dist/fixtures/assessmentFixtures.d.ts.map +1 -0
- package/dist/fixtures/assessmentFixtures.js +164 -0
- package/dist/formatCardExposureDisplay.d.ts +0 -4
- package/dist/formatCardExposureDisplay.d.ts.map +1 -1
- package/dist/formatCardExposureDisplay.js +0 -15
- package/dist/formatInsight.d.ts +3 -2
- package/dist/formatInsight.d.ts.map +1 -1
- package/dist/formatInsight.js +26 -1
- package/dist/index.d.ts +7 -11
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -11
- package/dist/narrativeParity.test.js +4 -34
- package/dist/presentGitHubPrComment.d.ts +1 -3
- package/dist/presentGitHubPrComment.d.ts.map +1 -1
- package/dist/presentGitHubPrComment.js +0 -17
- package/dist/presentation/buildGitHubCheckRunOutput.d.ts +20 -0
- package/dist/presentation/buildGitHubCheckRunOutput.d.ts.map +1 -0
- package/dist/presentation/buildGitHubCheckRunOutput.js +42 -0
- package/dist/presentation/buildGitHubCheckRunOutput.test.d.ts +2 -0
- package/dist/presentation/buildGitHubCheckRunOutput.test.d.ts.map +1 -0
- package/dist/presentation/buildGitHubCheckRunOutput.test.js +188 -0
- package/dist/presentation/compose/narrativeChannels.d.ts.map +1 -1
- package/dist/presentation/compose/narrativeChannels.js +13 -43
- package/dist/presentation/compose/narrativeCompose.d.ts.map +1 -1
- package/dist/presentation/compose/narrativeCompose.js +2 -5
- package/dist/presentation/dto/assessmentPresentationFields.d.ts +13 -0
- package/dist/presentation/dto/assessmentPresentationFields.d.ts.map +1 -0
- package/dist/presentation/dto/assessmentPresentationFields.js +1 -0
- package/dist/presentation/dto/dashboardCardPresentation.d.ts +2 -1
- package/dist/presentation/dto/dashboardCardPresentation.d.ts.map +1 -1
- package/dist/presentation/dto/githubAndCliPresentation.d.ts +4 -3
- package/dist/presentation/dto/githubAndCliPresentation.d.ts.map +1 -1
- package/dist/presentation/dto/scanDetailsPresentation.d.ts +2 -1
- package/dist/presentation/dto/scanDetailsPresentation.d.ts.map +1 -1
- package/dist/presentation/fixtures/dashboardCardGolden.test.js +21 -14
- package/dist/presentation/fixtures/presentationPersonaFixtures.d.ts.map +1 -1
- package/dist/presentation/fixtures/presentationPersonaFixtures.js +31 -24
- package/dist/presentation/fixtures/scanResultFixtures.d.ts.map +1 -1
- package/dist/presentation/fixtures/scanResultFixtures.js +14 -3
- package/dist/presentation/index.d.ts +2 -2
- package/dist/presentation/index.d.ts.map +1 -1
- package/dist/presentation/index.js +2 -2
- package/dist/presentation/orchestration/buildScanCardPresentation.d.ts.map +1 -1
- package/dist/presentation/orchestration/buildScanCardPresentation.js +8 -3
- package/dist/presentation/orchestration/buildScanPresentationBundle.d.ts +1 -1
- package/dist/presentation/orchestration/buildScanPresentationBundle.d.ts.map +1 -1
- package/dist/presentation/orchestration/buildScanPresentationBundle.js +12 -10
- package/dist/presentation/orchestration/scanPresentationBundle.d.ts +8 -3
- package/dist/presentation/orchestration/scanPresentationBundle.d.ts.map +1 -1
- package/dist/presentation/presentationPersonas.test.js +6 -6
- package/dist/presentation/presenters/presentCliScanSummary.d.ts.map +1 -1
- package/dist/presentation/presenters/presentCliScanSummary.js +2 -0
- package/dist/presentation/presenters/presentDashboardCard.d.ts +1 -0
- package/dist/presentation/presenters/presentDashboardCard.d.ts.map +1 -1
- package/dist/presentation/presenters/presentDashboardCard.js +18 -0
- package/dist/presentation/presenters/presentGitHubCheckRun.d.ts.map +1 -1
- package/dist/presentation/presenters/presentGitHubCheckRun.js +2 -0
- package/dist/presentation/presenters/presentGitHubPrComment.d.ts.map +1 -1
- package/dist/presentation/presenters/presentGitHubPrComment.js +15 -21
- package/dist/presentation/presenters/presentScanDetails.d.ts.map +1 -1
- package/dist/presentation/presenters/presentScanDetails.js +52 -129
- package/dist/presentation/profile/buildProfileFromAssessment.d.ts +5 -0
- package/dist/presentation/profile/buildProfileFromAssessment.d.ts.map +1 -0
- package/dist/presentation/profile/buildProfileFromAssessment.js +58 -0
- package/dist/presentation/projectAssessmentFields.d.ts +4 -0
- package/dist/presentation/projectAssessmentFields.d.ts.map +1 -0
- package/dist/presentation/projectAssessmentFields.js +13 -0
- package/dist/presentation/surfaceParity.test.d.ts +2 -0
- package/dist/presentation/surfaceParity.test.d.ts.map +1 -0
- package/dist/presentation/surfaceParity.test.js +74 -0
- package/dist/productMessaging.d.ts +4 -4
- package/dist/productMessaging.d.ts.map +1 -1
- package/dist/productMessaging.js +4 -4
- package/dist/productMessaging.test.js +2 -2
- package/dist/repoIntelligenceSchema.d.ts +2 -2
- package/dist/resolvePipelineStatus.d.ts +15 -0
- package/dist/resolvePipelineStatus.d.ts.map +1 -0
- package/dist/resolvePipelineStatus.js +37 -0
- package/dist/scanCardPresentationState.d.ts +10 -0
- package/dist/scanCardPresentationState.d.ts.map +1 -0
- package/dist/scanCardPresentationState.js +4 -0
- package/dist/{scanDetailViewModel.d.ts → scanDetailViewModelTypes.d.ts} +60 -32
- package/dist/scanDetailViewModelTypes.d.ts.map +1 -0
- package/dist/scanDetailViewModelTypes.js +4 -0
- package/dist/scanResultSchema.d.ts +75 -2
- package/dist/scanResultSchema.d.ts.map +1 -1
- package/dist/scanResultSchema.js +4 -2
- package/dist/scanResultSchema.test.js +16 -0
- package/dist/scanSurfaceCopy.d.ts +2 -0
- package/dist/scanSurfaceCopy.d.ts.map +1 -1
- package/dist/scanSurfaceCopy.js +2 -0
- package/dist/trustedScanGuards.test.js +7 -0
- package/dist/types.d.ts +3 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/dist/collectNarrativeWhyBullets.d.ts +0 -12
- package/dist/collectNarrativeWhyBullets.d.ts.map +0 -1
- package/dist/collectNarrativeWhyBullets.js +0 -104
- package/dist/deriveCardDisplaySummary.d.ts +0 -16
- package/dist/deriveCardDisplaySummary.d.ts.map +0 -1
- package/dist/deriveCardDisplaySummary.js +0 -56
- package/dist/deriveCardDisplaySummary.test.d.ts +0 -2
- package/dist/deriveCardDisplaySummary.test.d.ts.map +0 -1
- package/dist/deriveCardDisplaySummary.test.js +0 -89
- package/dist/deriveCardOperationalObservations.d.ts +0 -19
- package/dist/deriveCardOperationalObservations.d.ts.map +0 -1
- package/dist/deriveCardOperationalObservations.js +0 -180
- package/dist/deriveCardOperationalObservations.test.d.ts +0 -2
- package/dist/deriveCardOperationalObservations.test.d.ts.map +0 -1
- package/dist/deriveCardOperationalObservations.test.js +0 -268
- package/dist/deriveRiskScoreSummary.d.ts +0 -33
- package/dist/deriveRiskScoreSummary.d.ts.map +0 -1
- package/dist/deriveRiskScoreSummary.js +0 -90
- package/dist/deriveRiskScoreSummary.test.d.ts +0 -2
- package/dist/deriveRiskScoreSummary.test.d.ts.map +0 -1
- package/dist/deriveRiskScoreSummary.test.js +0 -47
- package/dist/deriveScanDetailRecommendations.d.ts +0 -63
- package/dist/deriveScanDetailRecommendations.d.ts.map +0 -1
- package/dist/deriveScanDetailRecommendations.js +0 -725
- package/dist/deriveScanDetailRecommendations.test.d.ts +0 -2
- package/dist/deriveScanDetailRecommendations.test.d.ts.map +0 -1
- package/dist/deriveScanDetailRecommendations.test.js +0 -181
- package/dist/deriveScanSummaryText.d.ts +0 -7
- package/dist/deriveScanSummaryText.d.ts.map +0 -1
- package/dist/deriveScanSummaryText.js +0 -24
- package/dist/deriveScanSummaryText.test.d.ts +0 -2
- package/dist/deriveScanSummaryText.test.d.ts.map +0 -1
- package/dist/deriveScanSummaryText.test.js +0 -77
- package/dist/formatCardEvidenceCounts.d.ts +0 -7
- package/dist/formatCardEvidenceCounts.d.ts.map +0 -1
- package/dist/formatCardEvidenceCounts.js +0 -19
- package/dist/prCheckRunPresentation.d.ts +0 -68
- package/dist/prCheckRunPresentation.d.ts.map +0 -1
- package/dist/prCheckRunPresentation.js +0 -319
- package/dist/prCheckRunPresentation.test.d.ts +0 -2
- package/dist/prCheckRunPresentation.test.d.ts.map +0 -1
- package/dist/prCheckRunPresentation.test.js +0 -278
- package/dist/presentation/intent/derivePresentationInterpretation.d.ts +0 -4
- package/dist/presentation/intent/derivePresentationInterpretation.d.ts.map +0 -1
- package/dist/presentation/intent/derivePresentationInterpretation.js +0 -202
- package/dist/presentation/intent/formatPresentationCopy.d.ts +0 -8
- package/dist/presentation/intent/formatPresentationCopy.d.ts.map +0 -1
- package/dist/presentation/intent/formatPresentationCopy.js +0 -140
- package/dist/presentation/intent/presentationIntent.test.d.ts +0 -2
- package/dist/presentation/intent/presentationIntent.test.d.ts.map +0 -1
- package/dist/presentation/intent/presentationIntent.test.js +0 -29
- package/dist/presentation/intent/verificationFocusLabels.d.ts +0 -2
- package/dist/presentation/intent/verificationFocusLabels.d.ts.map +0 -1
- package/dist/presentation/intent/verificationFocusLabels.js +0 -45
- package/dist/presentation/profile/derivePresentationProfile.d.ts +0 -12
- package/dist/presentation/profile/derivePresentationProfile.d.ts.map +0 -1
- package/dist/presentation/profile/derivePresentationProfile.js +0 -85
- package/dist/scanCardSummary.d.ts +0 -58
- package/dist/scanCardSummary.d.ts.map +0 -1
- package/dist/scanCardSummary.js +0 -146
- package/dist/scanCardSummary.test.d.ts +0 -2
- package/dist/scanCardSummary.test.d.ts.map +0 -1
- package/dist/scanCardSummary.test.js +0 -234
- package/dist/scanDetailViewModel.d.ts.map +0 -1
- package/dist/scanDetailViewModel.js +0 -636
- package/dist/scanDetailViewModel.test.d.ts +0 -2
- package/dist/scanDetailViewModel.test.d.ts.map +0 -1
- package/dist/scanDetailViewModel.test.js +0 -530
|
@@ -1,34 +1,28 @@
|
|
|
1
1
|
import { MERGE_POSTURE_LABEL } from "../../riskVocabulary.js";
|
|
2
|
-
import {
|
|
3
|
-
import { formatChangedPackagesShort
|
|
2
|
+
import { buildNarrativeChannels, evidenceContextFromProfile, } from "../compose/narrativeCompose.js";
|
|
3
|
+
import { formatChangedPackagesShort } from "../../narrativePresentation.js";
|
|
4
|
+
import { projectAssessmentFields } from "../projectAssessmentFields.js";
|
|
4
5
|
export function presentGitHubPrComment(bundle) {
|
|
5
6
|
const { facts, profile } = bundle;
|
|
7
|
+
const channels = buildNarrativeChannels(bundle);
|
|
8
|
+
const assessmentFields = projectAssessmentFields(bundle);
|
|
6
9
|
const introLines = [];
|
|
7
10
|
const changed = formatChangedPackagesShort(facts, 3);
|
|
8
11
|
if (changed)
|
|
9
12
|
introLines.push(`Changed: ${changed}`);
|
|
10
|
-
const
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
const verify =
|
|
13
|
+
for (const line of assessmentFields.reasoning.slice(0, 2)) {
|
|
14
|
+
introLines.push(line);
|
|
15
|
+
}
|
|
16
|
+
const verify = channels.verification[0];
|
|
14
17
|
if (verify)
|
|
15
18
|
introLines.push(`Verify: ${verify}`);
|
|
16
|
-
const
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
const where = g.context?.trim() ||
|
|
22
|
-
facts.packageUsage
|
|
23
|
-
.flatMap((u) => u.paths.slice(0, 1))
|
|
24
|
-
.filter(Boolean)[0] ||
|
|
25
|
-
"See scan detail for affected paths.";
|
|
26
|
-
const action = g.remediation?.trim() ||
|
|
27
|
-
composeVerificationActions(bundle, 1)[0] ||
|
|
28
|
-
"Review before merge.";
|
|
29
|
-
return { message: g.message, where, action };
|
|
30
|
-
});
|
|
19
|
+
const guidanceBlocks = channels.verification.slice(0, 3).map((action) => ({
|
|
20
|
+
message: assessmentFields.reasoning[0] ?? action,
|
|
21
|
+
where: changed ?? "See scan detail for affected paths.",
|
|
22
|
+
action,
|
|
23
|
+
}));
|
|
31
24
|
return {
|
|
25
|
+
...assessmentFields,
|
|
32
26
|
status: profile.status,
|
|
33
27
|
density: profile.density,
|
|
34
28
|
confidence: profile.confidence,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"presentScanDetails.d.ts","sourceRoot":"","sources":["../../../src/presentation/presenters/presentScanDetails.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"presentScanDetails.d.ts","sourceRoot":"","sources":["../../../src/presentation/presenters/presentScanDetails.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,mCAAmC,CAAC;AACjF,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,4CAA4C,CAAC;AAGzF,MAAM,MAAM,yBAAyB,GAAG;IACtC,MAAM,EAAE,MAAM,CAAC;IACf,kBAAkB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B,CAAC;AAmDF,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,sBAAsB,EAC9B,GAAG,EAAE,yBAAyB,GAC7B,uBAAuB,CAwEzB"}
|
|
@@ -1,88 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { MERGE_CONCERN_LABELS } from "../../assessmentLabels.js";
|
|
2
2
|
import { MERGE_POSTURE_LABEL } from "../../riskVocabulary.js";
|
|
3
|
-
import {
|
|
4
|
-
import { buildNarrativeChannels, composeHeadline, composeSubheadline, composeSupportingContext, composeVerificationActions, evidenceContextFromProfile, projectCompactKeyPoints, } from "../compose/narrativeCompose.js";
|
|
3
|
+
import { buildNarrativeChannels, composeSubheadline, composeSupportingContext, evidenceContextFromProfile, projectCompactKeyPoints, } from "../compose/narrativeCompose.js";
|
|
5
4
|
import { normalizeGeneratedText, normalizeGeneratedTextNullable, } from "../../normalizeGeneratedText.js";
|
|
6
5
|
import { scanSurfaceCopy } from "../../scanSurfaceCopy.js";
|
|
7
|
-
|
|
8
|
-
const oi = vm.operationalImpact;
|
|
9
|
-
if (oi.status === "hidden") {
|
|
10
|
-
return { status: "hidden", items: [] };
|
|
11
|
-
}
|
|
12
|
-
if (oi.status === "rich") {
|
|
13
|
-
return {
|
|
14
|
-
status: "rich",
|
|
15
|
-
items: oi.items.map((item) => ({
|
|
16
|
-
message: item.message,
|
|
17
|
-
where: item.where,
|
|
18
|
-
verify: item.verify,
|
|
19
|
-
affectedFiles: item.affectedFiles,
|
|
20
|
-
})),
|
|
21
|
-
};
|
|
22
|
-
}
|
|
23
|
-
return {
|
|
24
|
-
status: "compact",
|
|
25
|
-
items: oi.items,
|
|
26
|
-
fallbackMessage: oi.fallbackMessage,
|
|
27
|
-
};
|
|
28
|
-
}
|
|
29
|
-
function mapRecommendations(vm) {
|
|
30
|
-
const items = vm.recommendedActions.items.map((item) => ({
|
|
31
|
-
rank: item.rank,
|
|
32
|
-
title: item.title,
|
|
33
|
-
priority: item.priority === "high" ||
|
|
34
|
-
item.priority === "medium" ||
|
|
35
|
-
item.priority === "low"
|
|
36
|
-
? item.priority
|
|
37
|
-
: "medium",
|
|
38
|
-
rationale: item.detail?.why,
|
|
39
|
-
}));
|
|
40
|
-
return { items };
|
|
41
|
-
}
|
|
42
|
-
function mapEvidence(bundle, vm) {
|
|
43
|
-
const defaultCollapsed = bundle.profile.priority === "pr_intelligence" &&
|
|
44
|
-
bundle.profile.density === "rich";
|
|
45
|
-
const ev = vm.evidence;
|
|
46
|
-
if (!ev) {
|
|
47
|
-
return {
|
|
48
|
-
defaultCollapsed,
|
|
49
|
-
attentionAreas: [],
|
|
50
|
-
findings: [],
|
|
51
|
-
findingsOverflowCount: 0,
|
|
52
|
-
};
|
|
53
|
-
}
|
|
54
|
-
return {
|
|
55
|
-
defaultCollapsed,
|
|
56
|
-
attentionAreas: ev.attentionAreas.map((area) => ({
|
|
57
|
-
problemLabel: area.problemLabel,
|
|
58
|
-
problemDescription: area.problemDescription,
|
|
59
|
-
packages: area.packages.map((p) => ({
|
|
60
|
-
name: p.name,
|
|
61
|
-
version: p.version,
|
|
62
|
-
direct: p.direct,
|
|
63
|
-
severity: p.severity,
|
|
64
|
-
evidence: p.evidence,
|
|
65
|
-
})),
|
|
66
|
-
overflowCount: area.overflowCount,
|
|
67
|
-
})),
|
|
68
|
-
findings: ev.findings.map((f) => ({
|
|
69
|
-
id: f.id,
|
|
70
|
-
severity: f.severity,
|
|
71
|
-
title: f.title,
|
|
72
|
-
description: f.description,
|
|
73
|
-
packageName: f.packageName,
|
|
74
|
-
recommendation: f.recommendation,
|
|
75
|
-
source: f.source,
|
|
76
|
-
})),
|
|
77
|
-
findingsOverflowCount: ev.findingsOverflowCount,
|
|
78
|
-
topology: ev.topology
|
|
79
|
-
? {
|
|
80
|
-
summaryLine: ev.topology.summaryLine,
|
|
81
|
-
deepest: ev.topology.deepest,
|
|
82
|
-
}
|
|
83
|
-
: undefined,
|
|
84
|
-
};
|
|
85
|
-
}
|
|
6
|
+
import { projectAssessmentFields } from "../projectAssessmentFields.js";
|
|
86
7
|
function mapUsage(bundle) {
|
|
87
8
|
const { facts } = bundle;
|
|
88
9
|
if (facts.packageUsage.length === 0 && facts.frameworks.length === 0) {
|
|
@@ -101,20 +22,31 @@ function mapUsage(bundle) {
|
|
|
101
22
|
frameworks: facts.frameworks,
|
|
102
23
|
};
|
|
103
24
|
}
|
|
25
|
+
function mapEvidence(bundle) {
|
|
26
|
+
const defaultCollapsed = bundle.profile.priority === "pr_intelligence" &&
|
|
27
|
+
bundle.profile.density === "rich";
|
|
28
|
+
const findings = (bundle.result.findings ?? []).slice(0, 8).map((f) => ({
|
|
29
|
+
id: f.id,
|
|
30
|
+
severity: f.severity,
|
|
31
|
+
title: f.title,
|
|
32
|
+
description: f.description,
|
|
33
|
+
packageName: f.packageName,
|
|
34
|
+
recommendation: f.recommendation,
|
|
35
|
+
source: "dependency",
|
|
36
|
+
}));
|
|
37
|
+
return {
|
|
38
|
+
defaultCollapsed,
|
|
39
|
+
attentionAreas: [],
|
|
40
|
+
findings,
|
|
41
|
+
findingsOverflowCount: Math.max(0, (bundle.result.findings?.length ?? 0) - findings.length),
|
|
42
|
+
};
|
|
43
|
+
}
|
|
104
44
|
export function presentScanDetails(bundle, ctx) {
|
|
105
|
-
const { facts, profile, result } = bundle;
|
|
106
|
-
const
|
|
107
|
-
scanId: ctx.scanId,
|
|
108
|
-
status: "done",
|
|
109
|
-
methodologyVersion: ctx.methodologyVersion,
|
|
110
|
-
prNumber: ctx.prNumber,
|
|
111
|
-
repoContext: { status: "hidden" },
|
|
112
|
-
});
|
|
113
|
-
const headline = composeHeadline(bundle);
|
|
114
|
-
const subheadline = composeSubheadline(bundle);
|
|
45
|
+
const { assessment, facts, profile, result } = bundle;
|
|
46
|
+
const assessmentFields = projectAssessmentFields(bundle);
|
|
115
47
|
const channels = buildNarrativeChannels(bundle);
|
|
116
48
|
const keyPoints = projectCompactKeyPoints(channels, 6);
|
|
117
|
-
const
|
|
49
|
+
const subheadline = composeSubheadline(bundle);
|
|
118
50
|
const supportingLines = composeSupportingContext(bundle);
|
|
119
51
|
const supportingContext = supportingLines
|
|
120
52
|
? {
|
|
@@ -122,28 +54,39 @@ export function presentScanDetails(bundle, ctx) {
|
|
|
122
54
|
lines: supportingLines,
|
|
123
55
|
}
|
|
124
56
|
: undefined;
|
|
125
|
-
const
|
|
126
|
-
const
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
:
|
|
57
|
+
const postureLabel = MERGE_POSTURE_LABEL[profile.status];
|
|
58
|
+
const verdictLine = assessmentFields.reasoning[0] ??
|
|
59
|
+
(assessment.primaryConcern
|
|
60
|
+
? MERGE_CONCERN_LABELS[assessment.primaryConcern]
|
|
61
|
+
: postureLabel);
|
|
62
|
+
const verificationActions = channels.verification.map((title, index) => ({
|
|
63
|
+
title: normalizeGeneratedText(title),
|
|
64
|
+
detail: assessmentFields.reasoning[index + 1],
|
|
65
|
+
}));
|
|
66
|
+
const recommendations = verificationActions.map((action, index) => ({
|
|
67
|
+
rank: index + 1,
|
|
68
|
+
title: action.title,
|
|
69
|
+
priority: profile.status === "risky"
|
|
70
|
+
? "high"
|
|
71
|
+
: profile.status === "needs_review"
|
|
72
|
+
? "medium"
|
|
73
|
+
: "low",
|
|
74
|
+
rationale: action.detail,
|
|
75
|
+
}));
|
|
132
76
|
return {
|
|
77
|
+
...assessmentFields,
|
|
133
78
|
evidenceContext: evidenceContextFromProfile(bundle),
|
|
134
79
|
status: profile.status,
|
|
135
80
|
density: profile.density,
|
|
136
81
|
confidence: profile.confidence,
|
|
137
82
|
presentationIntent: profile.interpretation.intent,
|
|
138
83
|
hero: {
|
|
139
|
-
headline: normalizeGeneratedText(headline),
|
|
84
|
+
headline: normalizeGeneratedText(channels.headline),
|
|
140
85
|
subheadline: normalizeGeneratedTextNullable(subheadline) ?? undefined,
|
|
141
86
|
verdictLine: normalizeGeneratedText(verdictLine),
|
|
142
|
-
scopeChip: channels.reachLabel
|
|
143
|
-
deriveDetailReachChip(result.totalScore) ??
|
|
144
|
-
undefined,
|
|
87
|
+
scopeChip: channels.reachLabel,
|
|
145
88
|
postureLabel,
|
|
146
|
-
riskIndex:
|
|
89
|
+
riskIndex: result.totalScore,
|
|
147
90
|
},
|
|
148
91
|
narrative: {
|
|
149
92
|
keyPoints: keyPoints.map((k) => normalizeGeneratedText(k)),
|
|
@@ -151,30 +94,10 @@ export function presentScanDetails(bundle, ctx) {
|
|
|
151
94
|
primaryPackage: facts.changedPackages.primary ?? undefined,
|
|
152
95
|
},
|
|
153
96
|
usage: mapUsage(bundle),
|
|
154
|
-
verification: {
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
},
|
|
159
|
-
signalSummary: vm.signalSummary
|
|
160
|
-
? {
|
|
161
|
-
riskIndex: vm.signalSummary.score,
|
|
162
|
-
band: vm.signalSummary.overallBand === "moderate"
|
|
163
|
-
? "medium"
|
|
164
|
-
: vm.signalSummary.overallBand === "high"
|
|
165
|
-
? "high"
|
|
166
|
-
: "low",
|
|
167
|
-
layers: vm.signalSummary.layers.map((l) => ({
|
|
168
|
-
layer: l.layer,
|
|
169
|
-
score: l.score,
|
|
170
|
-
band: l.concernLabel,
|
|
171
|
-
label: l.label,
|
|
172
|
-
})),
|
|
173
|
-
}
|
|
174
|
-
: undefined,
|
|
175
|
-
operationalImpact: mapOperationalImpact(vm),
|
|
176
|
-
recommendations: mapRecommendations(vm),
|
|
177
|
-
evidence: mapEvidence(bundle, vm),
|
|
97
|
+
verification: { actions: verificationActions },
|
|
98
|
+
operationalImpact: { status: "hidden", items: [] },
|
|
99
|
+
recommendations: { items: recommendations },
|
|
100
|
+
evidence: mapEvidence(bundle),
|
|
178
101
|
supportingContext,
|
|
179
102
|
metadata: {
|
|
180
103
|
scanId: ctx.scanId,
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { Assessment, AssessmentPresentationPublic } from "../../assessmentSchema.js";
|
|
2
|
+
import type { ScanResult } from "../../types.js";
|
|
3
|
+
import type { PresentationProfile } from "./presentationProfile.js";
|
|
4
|
+
export declare function buildProfileFromAssessment(assessment: Assessment, presentation: AssessmentPresentationPublic, result: ScanResult): PresentationProfile;
|
|
5
|
+
//# sourceMappingURL=buildProfileFromAssessment.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"buildProfileFromAssessment.d.ts","sourceRoot":"","sources":["../../../src/presentation/profile/buildProfileFromAssessment.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,UAAU,EACV,4BAA4B,EAC7B,MAAM,2BAA2B,CAAC;AAEnC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAIjD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAwCpE,wBAAgB,0BAA0B,CACxC,UAAU,EAAE,UAAU,EACtB,YAAY,EAAE,4BAA4B,EAC1C,MAAM,EAAE,UAAU,GACjB,mBAAmB,CAuBrB"}
|
|
@@ -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 @@
|
|
|
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,
|
|
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: "
|
|
72
|
-
readonly exposureCategoriesLead: "
|
|
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,
|
|
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;;;;;;;;;
|
|
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"}
|
package/dist/productMessaging.js
CHANGED
|
@@ -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,
|
|
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: "
|
|
87
|
-
exposureCategoriesLead: "
|
|
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,
|
|
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("
|
|
75
|
-
expect(text).not.toMatch(/
|
|
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,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dashboard PR card lifecycle — distinct from pipeline status.
|
|
3
|
+
*
|
|
4
|
+
* Pipeline / infrastructure: `scanning`, `analysis_failed`, `surfaces_incomplete`
|
|
5
|
+
* Product / assessment: `ready`, `stale`
|
|
6
|
+
* Absence: `not_scanned`
|
|
7
|
+
*/
|
|
8
|
+
export type ScanCardPresentationState = "not_scanned" | "scanning" | "analysis_failed" | "surfaces_incomplete" | "ready" | "stale";
|
|
9
|
+
export declare function staleScanSubline(): string;
|
|
10
|
+
//# sourceMappingURL=scanCardPresentationState.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scanCardPresentationState.d.ts","sourceRoot":"","sources":["../src/scanCardPresentationState.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,MAAM,MAAM,yBAAyB,GACjC,aAAa,GACb,UAAU,GACV,iBAAiB,GACjB,qBAAqB,GACrB,OAAO,GACP,OAAO,CAAC;AAIZ,wBAAgB,gBAAgB,IAAI,MAAM,CAEzC"}
|