@mergesignal/shared 0.8.1 → 0.9.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/deriveScanNarrative.test.js +2 -2
- package/dist/fixtures/engineAbi4Fixtures.d.ts +4 -0
- package/dist/fixtures/engineAbi4Fixtures.d.ts.map +1 -0
- package/dist/fixtures/engineAbi4Fixtures.js +5 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/prRiskBand.d.ts +23 -0
- package/dist/prRiskBand.d.ts.map +1 -0
- package/dist/prRiskBand.js +66 -0
- package/dist/prRiskBand.test.d.ts +2 -0
- package/dist/prRiskBand.test.d.ts.map +1 -0
- package/dist/prRiskBand.test.js +57 -0
- package/dist/prRiskWire.d.ts +57 -0
- package/dist/prRiskWire.d.ts.map +1 -0
- package/dist/prRiskWire.js +98 -0
- package/dist/prRiskWire.test.d.ts +2 -0
- package/dist/prRiskWire.test.d.ts.map +1 -0
- package/dist/prRiskWire.test.js +106 -0
- package/dist/presentGitHubPrComment.d.ts.map +1 -1
- package/dist/presentGitHubPrComment.js +0 -1
- package/dist/presentation/dto/githubAndCliPresentation.d.ts +3 -0
- package/dist/presentation/dto/githubAndCliPresentation.d.ts.map +1 -1
- package/dist/presentation/dto/scanDetailsPresentation.d.ts +5 -2
- package/dist/presentation/dto/scanDetailsPresentation.d.ts.map +1 -1
- package/dist/presentation/orchestration/buildScanCardPresentation.d.ts +2 -1
- package/dist/presentation/orchestration/buildScanCardPresentation.d.ts.map +1 -1
- package/dist/presentation/orchestration/buildScanCardPresentation.js +7 -6
- package/dist/presentation/orchestration/buildScanDetailsPresentation.d.ts +1 -1
- package/dist/presentation/orchestration/buildScanDetailsPresentation.d.ts.map +1 -1
- package/dist/presentation/orchestration/buildScanDetailsPresentation.js +0 -1
- package/dist/presentation/orchestration/buildScanPresentationBundle.d.ts +0 -1
- package/dist/presentation/orchestration/buildScanPresentationBundle.d.ts.map +1 -1
- package/dist/presentation/presenters/presentCliScanSummary.d.ts.map +1 -1
- package/dist/presentation/presenters/presentCliScanSummary.js +9 -4
- package/dist/presentation/presenters/presentGitHubCheckRun.d.ts.map +1 -1
- package/dist/presentation/presenters/presentGitHubCheckRun.js +10 -0
- package/dist/presentation/presenters/presentGitHubPrComment.d.ts.map +1 -1
- package/dist/presentation/presenters/presentGitHubPrComment.js +6 -0
- package/dist/presentation/presenters/presentScanDetails.d.ts.map +1 -1
- package/dist/presentation/presenters/presentScanDetails.js +46 -3
- package/dist/presentation/render/renderCliScanSummaryText.d.ts.map +1 -1
- package/dist/presentation/render/renderCliScanSummaryText.js +4 -1
- package/dist/productMessaging.d.ts +2 -2
- package/dist/productMessaging.d.ts.map +1 -1
- package/dist/productMessaging.js +3 -3
- package/dist/productMessaging.test.js +6 -6
- package/dist/resolvePipelineStatus.d.ts +4 -3
- package/dist/resolvePipelineStatus.d.ts.map +1 -1
- package/dist/resolvePipelineStatus.js +3 -3
- package/dist/riskSignals.d.ts +6 -6
- package/dist/riskSignals.d.ts.map +1 -1
- package/dist/riskSignals.js +9 -10
- package/dist/riskVocabulary.js +7 -7
- package/dist/scanPresentationBundle.golden.test.js +3 -3
- package/dist/scanResultSchema.d.ts +42 -1
- package/dist/scanResultSchema.d.ts.map +1 -1
- package/dist/scanResultSchema.js +35 -2
- package/dist/scanResultSchema.test.js +15 -2
- package/dist/scanSurfaceCopy.d.ts +4 -2
- package/dist/scanSurfaceCopy.d.ts.map +1 -1
- package/dist/scanSurfaceCopy.js +4 -2
- package/dist/trustedScanGuards.test.js +3 -2
- package/dist/types.d.ts +17 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/dist/formatCardExposureDisplay.d.ts +0 -22
- package/dist/formatCardExposureDisplay.d.ts.map +0 -1
- package/dist/formatCardExposureDisplay.js +0 -63
- package/dist/formatCardExposureDisplay.test.d.ts +0 -2
- package/dist/formatCardExposureDisplay.test.d.ts.map +0 -1
- package/dist/formatCardExposureDisplay.test.js +0 -44
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"buildScanDetailsPresentation.d.ts","sourceRoot":"","sources":["../../../src/presentation/orchestration/buildScanDetailsPresentation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACtD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAGjD,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,mCAAmC,CAAC;AAEjF,MAAM,MAAM,iCAAiC,GAAG;IAC9C,MAAM,EAAE,MAAM,CAAC;IACf,cAAc,EAAE,cAAc,CAAC;IAC/B,MAAM,EAAE,UAAU,CAAC;IACnB,kBAAkB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,
|
|
1
|
+
{"version":3,"file":"buildScanDetailsPresentation.d.ts","sourceRoot":"","sources":["../../../src/presentation/orchestration/buildScanDetailsPresentation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACtD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAGjD,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,mCAAmC,CAAC;AAEjF,MAAM,MAAM,iCAAiC,GAAG;IAC9C,MAAM,EAAE,MAAM,CAAC;IACf,cAAc,EAAE,cAAc,CAAC;IAC/B,MAAM,EAAE,UAAU,CAAC;IACnB,kBAAkB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7B,CAAC;AAEF,wBAAgB,4BAA4B,CAC1C,KAAK,EAAE,iCAAiC,GACvC,uBAAuB,GAAG,IAAI,CAgBhC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"buildScanPresentationBundle.d.ts","sourceRoot":"","sources":["../../../src/presentation/orchestration/buildScanPresentationBundle.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAEtD,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AAE1E,MAAM,MAAM,gCAAgC,GAAG;IAC7C,MAAM,EAAE,UAAU,CAAC;IACnB,cAAc,EAAE,cAAc,CAAC;IAC/B,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"buildScanPresentationBundle.d.ts","sourceRoot":"","sources":["../../../src/presentation/orchestration/buildScanPresentationBundle.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAEtD,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AAE1E,MAAM,MAAM,gCAAgC,GAAG;IAC7C,MAAM,EAAE,UAAU,CAAC;IACnB,cAAc,EAAE,cAAc,CAAC;IAC/B,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B,CAAC;AAEF;;;GAGG;AACH,wBAAgB,2BAA2B,CACzC,KAAK,EAAE,gCAAgC,GACtC,sBAAsB,GAAG,IAAI,CA4B/B"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"presentCliScanSummary.d.ts","sourceRoot":"","sources":["../../../src/presentation/presenters/presentCliScanSummary.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"presentCliScanSummary.d.ts","sourceRoot":"","sources":["../../../src/presentation/presenters/presentCliScanSummary.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,oCAAoC,CAAC;AAC9E,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,4CAA4C,CAAC;AAGzF,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,sBAAsB,EAC9B,GAAG,GAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAA;CAAO,GAC/B,mBAAmB,CAiCrB"}
|
|
@@ -1,11 +1,14 @@
|
|
|
1
|
+
import { scoreToBandLabel } from "../../prRiskBand.js";
|
|
2
|
+
import { resolvePrRiskLayerScores } from "../../prRiskWire.js";
|
|
1
3
|
import { buildNarrativeChannels, composeHeadline, composeSubheadline, composeSupportingContext, composeVerificationActions, evidenceContextFromProfile, projectCompactKeyPoints, } from "../compose/narrativeCompose.js";
|
|
2
4
|
import { projectAssessmentFields } from "../projectAssessmentFields.js";
|
|
3
5
|
export function presentCliScanSummary(bundle, ctx = {}) {
|
|
4
6
|
const { facts, profile, result } = bundle;
|
|
5
|
-
const
|
|
6
|
-
const layerLine =
|
|
7
|
-
? `security=${
|
|
7
|
+
const layerScores = resolvePrRiskLayerScores(result);
|
|
8
|
+
const layerLine = layerScores
|
|
9
|
+
? `security=${layerScores.security} maintainability=${layerScores.maintainability} ecosystem=${layerScores.ecosystem} upgradeImpact=${layerScores.upgradeImpact}`
|
|
8
10
|
: "";
|
|
11
|
+
const prRiskScore = facts.riskIndex ?? 0;
|
|
9
12
|
return {
|
|
10
13
|
...projectAssessmentFields(bundle),
|
|
11
14
|
header: {
|
|
@@ -22,7 +25,9 @@ export function presentCliScanSummary(bundle, ctx = {}) {
|
|
|
22
25
|
keyPoints: projectCompactKeyPoints(buildNarrativeChannels(bundle), 6),
|
|
23
26
|
verificationActions: composeVerificationActions(bundle, 5),
|
|
24
27
|
metrics: {
|
|
25
|
-
|
|
28
|
+
prRiskScore,
|
|
29
|
+
prRiskBandLabel: scoreToBandLabel(prRiskScore) ?? undefined,
|
|
30
|
+
riskIndex: prRiskScore,
|
|
26
31
|
layerLine,
|
|
27
32
|
findingCount: result.findings?.length ?? 0,
|
|
28
33
|
recommendationCount: result.recommendations?.length ?? 0,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"presentGitHubCheckRun.d.ts","sourceRoot":"","sources":["../../../src/presentation/presenters/presentGitHubCheckRun.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"presentGitHubCheckRun.d.ts","sourceRoot":"","sources":["../../../src/presentation/presenters/presentGitHubCheckRun.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,oCAAoC,CAAC;AACrF,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,4CAA4C,CAAC;AAGzF,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,sBAAsB,EAC9B,GAAG,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,OAAO,CAAA;CAAE,GAChE,0BAA0B,CA4C5B"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { scoreToBandLabel } from "../../prRiskBand.js";
|
|
1
2
|
import { buildNarrativeChannels, composeHeadline, composeSubheadline, composeVerificationActions, evidenceContextFromProfile, projectCompactKeyPoints, } from "../compose/narrativeCompose.js";
|
|
2
3
|
import { projectAssessmentFields } from "../projectAssessmentFields.js";
|
|
3
4
|
export function presentGitHubCheckRun(bundle, ctx) {
|
|
@@ -12,6 +13,15 @@ export function presentGitHubCheckRun(bundle, ctx) {
|
|
|
12
13
|
? "failure"
|
|
13
14
|
: "neutral";
|
|
14
15
|
const sections = [];
|
|
16
|
+
const prRiskScore = bundle.facts.riskSignals?.riskIndex;
|
|
17
|
+
const prRiskBandLabelText = scoreToBandLabel(prRiskScore);
|
|
18
|
+
if (prRiskScore != null && prRiskBandLabelText) {
|
|
19
|
+
sections.push({
|
|
20
|
+
id: "why",
|
|
21
|
+
title: "PR Risk",
|
|
22
|
+
bullets: [`${prRiskScore} (${prRiskBandLabelText})`],
|
|
23
|
+
});
|
|
24
|
+
}
|
|
15
25
|
if (keyPoints.length > 0) {
|
|
16
26
|
sections.push({ id: "why", title: "Why", bullets: keyPoints });
|
|
17
27
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"presentGitHubPrComment.d.ts","sourceRoot":"","sources":["../../../src/presentation/presenters/presentGitHubPrComment.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"presentGitHubPrComment.d.ts","sourceRoot":"","sources":["../../../src/presentation/presenters/presentGitHubPrComment.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,oCAAoC,CAAC;AACtF,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,4CAA4C,CAAC;AAGzF,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,sBAAsB,GAC7B,2BAA2B,CAmC7B"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { MERGE_POSTURE_LABEL } from "../../riskVocabulary.js";
|
|
2
|
+
import { scoreToBandLabel } from "../../prRiskBand.js";
|
|
2
3
|
import { buildNarrativeChannels, evidenceContextFromProfile, } from "../compose/narrativeCompose.js";
|
|
3
4
|
import { formatChangedPackagesShort } from "../../narrativePresentation.js";
|
|
4
5
|
import { projectAssessmentFields } from "../projectAssessmentFields.js";
|
|
@@ -10,6 +11,11 @@ export function presentGitHubPrComment(bundle) {
|
|
|
10
11
|
const changed = formatChangedPackagesShort(facts, 3);
|
|
11
12
|
if (changed)
|
|
12
13
|
introLines.push(`Changed: ${changed}`);
|
|
14
|
+
const prRiskScore = bundle.facts.riskSignals?.riskIndex;
|
|
15
|
+
const prRiskBandLabelText = scoreToBandLabel(prRiskScore);
|
|
16
|
+
if (prRiskScore != null && prRiskBandLabelText) {
|
|
17
|
+
introLines.push(`PR Risk: ${prRiskScore} (${prRiskBandLabelText})`);
|
|
18
|
+
}
|
|
13
19
|
for (const line of assessmentFields.reasoning.slice(0, 2)) {
|
|
14
20
|
introLines.push(line);
|
|
15
21
|
}
|
|
@@ -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":"AAqBA,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;AA6FF,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,sBAAsB,EAC9B,GAAG,EAAE,yBAAyB,GAC7B,uBAAuB,CAiFzB"}
|
|
@@ -1,10 +1,46 @@
|
|
|
1
1
|
import { MERGE_CONCERN_LABELS } from "../../assessmentLabels.js";
|
|
2
2
|
import { normalizedPackageUsagePaths } from "../../narrativePresentation.js";
|
|
3
|
+
import { prRiskBandLabel, prRiskBandToGaugeBand, scoreToBandLabel, } from "../../prRiskBand.js";
|
|
3
4
|
import { MERGE_POSTURE_LABEL } from "../../riskVocabulary.js";
|
|
4
5
|
import { buildNarrativeChannels, composeSubheadline, composeSupportingContext, evidenceContextFromProfile, projectCompactKeyPoints, } from "../compose/narrativeCompose.js";
|
|
5
6
|
import { normalizeGeneratedText, normalizeGeneratedTextNullable, } from "../../normalizeGeneratedText.js";
|
|
6
7
|
import { scanSurfaceCopy } from "../../scanSurfaceCopy.js";
|
|
7
8
|
import { projectAssessmentFields } from "../projectAssessmentFields.js";
|
|
9
|
+
const LAYER_LABEL = {
|
|
10
|
+
security: "Security",
|
|
11
|
+
maintainability: "Maintainability",
|
|
12
|
+
ecosystem: "Ecosystem",
|
|
13
|
+
upgradeImpact: "Upgrade impact",
|
|
14
|
+
};
|
|
15
|
+
function gaugeBandToSignalBand(band) {
|
|
16
|
+
if (band === "high")
|
|
17
|
+
return "high";
|
|
18
|
+
if (band === "moderate")
|
|
19
|
+
return "medium";
|
|
20
|
+
return "low";
|
|
21
|
+
}
|
|
22
|
+
function mapSignalSummary(bundle) {
|
|
23
|
+
const riskSignals = bundle.facts.riskSignals;
|
|
24
|
+
const prRiskScore = riskSignals?.riskIndex;
|
|
25
|
+
if (!riskSignals || prRiskScore == null || !Number.isFinite(prRiskScore)) {
|
|
26
|
+
return undefined;
|
|
27
|
+
}
|
|
28
|
+
const band = riskSignals.band;
|
|
29
|
+
if (!band)
|
|
30
|
+
return undefined;
|
|
31
|
+
const gaugeBand = prRiskBandToGaugeBand(band);
|
|
32
|
+
const signalBand = gaugeBandToSignalBand(gaugeBand);
|
|
33
|
+
return {
|
|
34
|
+
prRiskScore,
|
|
35
|
+
band: signalBand,
|
|
36
|
+
layers: riskSignals.layers.map((layer) => ({
|
|
37
|
+
layer: layer.layer,
|
|
38
|
+
score: layer.score,
|
|
39
|
+
band: gaugeBandToSignalBand(prRiskBandToGaugeBand(layer.band)),
|
|
40
|
+
label: LAYER_LABEL[layer.layer],
|
|
41
|
+
})),
|
|
42
|
+
};
|
|
43
|
+
}
|
|
8
44
|
function mapUsage(bundle) {
|
|
9
45
|
const { facts } = bundle;
|
|
10
46
|
if (facts.packageUsage.length === 0 && facts.frameworks.length === 0) {
|
|
@@ -43,7 +79,7 @@ function mapEvidence(bundle) {
|
|
|
43
79
|
};
|
|
44
80
|
}
|
|
45
81
|
export function presentScanDetails(bundle, ctx) {
|
|
46
|
-
const { assessment, facts, profile
|
|
82
|
+
const { assessment, facts, profile } = bundle;
|
|
47
83
|
const assessmentFields = projectAssessmentFields(bundle);
|
|
48
84
|
const channels = buildNarrativeChannels(bundle);
|
|
49
85
|
const keyPoints = projectCompactKeyPoints(channels, 6);
|
|
@@ -74,6 +110,10 @@ export function presentScanDetails(bundle, ctx) {
|
|
|
74
110
|
: "low",
|
|
75
111
|
rationale: action.detail,
|
|
76
112
|
}));
|
|
113
|
+
const prRiskScore = facts.riskSignals?.riskIndex ?? null;
|
|
114
|
+
const prRiskBandLabelText = facts.riskSignals?.band != null
|
|
115
|
+
? prRiskBandLabel(facts.riskSignals.band)
|
|
116
|
+
: scoreToBandLabel(prRiskScore);
|
|
77
117
|
return {
|
|
78
118
|
...assessmentFields,
|
|
79
119
|
evidenceContext: evidenceContextFromProfile(bundle),
|
|
@@ -87,8 +127,11 @@ export function presentScanDetails(bundle, ctx) {
|
|
|
87
127
|
verdictLine: normalizeGeneratedText(verdictLine),
|
|
88
128
|
scopeChip: channels.reachLabel,
|
|
89
129
|
postureLabel,
|
|
90
|
-
|
|
130
|
+
prRiskScore,
|
|
131
|
+
prRiskBandLabel: prRiskBandLabelText ?? undefined,
|
|
132
|
+
riskIndex: prRiskScore,
|
|
91
133
|
},
|
|
134
|
+
signalSummary: mapSignalSummary(bundle),
|
|
92
135
|
narrative: {
|
|
93
136
|
keyPoints: keyPoints.map((k) => normalizeGeneratedText(k)),
|
|
94
137
|
changedPackages: facts.changedPackages.all,
|
|
@@ -102,7 +145,7 @@ export function presentScanDetails(bundle, ctx) {
|
|
|
102
145
|
supportingContext,
|
|
103
146
|
metadata: {
|
|
104
147
|
scanId: ctx.scanId,
|
|
105
|
-
generatedAt: result.generatedAt,
|
|
148
|
+
generatedAt: bundle.result.generatedAt,
|
|
106
149
|
methodologyVersion: ctx.methodologyVersion,
|
|
107
150
|
changedPackagesSummary: facts.changedPackages.primary ?? facts.changedPackages.all.join(", "),
|
|
108
151
|
},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"renderCliScanSummaryText.d.ts","sourceRoot":"","sources":["../../../src/presentation/render/renderCliScanSummaryText.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,oCAAoC,CAAC;AAE9E,wBAAgB,wBAAwB,CAAC,CAAC,EAAE,mBAAmB,GAAG,MAAM,
|
|
1
|
+
{"version":3,"file":"renderCliScanSummaryText.d.ts","sourceRoot":"","sources":["../../../src/presentation/render/renderCliScanSummaryText.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,oCAAoC,CAAC;AAE9E,wBAAgB,wBAAwB,CAAC,CAAC,EAAE,mBAAmB,GAAG,MAAM,CAkCvE"}
|
|
@@ -9,7 +9,10 @@ export function renderCliScanSummaryText(p) {
|
|
|
9
9
|
lines.push(p.subheadline);
|
|
10
10
|
lines.push("", `Status: ${p.status} | Density: ${p.density} | Confidence: ${p.confidence}`);
|
|
11
11
|
if (p.metrics) {
|
|
12
|
-
|
|
12
|
+
const bandSuffix = p.metrics.prRiskBandLabel
|
|
13
|
+
? ` (${p.metrics.prRiskBandLabel})`
|
|
14
|
+
: "";
|
|
15
|
+
lines.push(`${scanSurfaceCopy.actions.prRiskScoreLabel}: ${p.metrics.prRiskScore}${bandSuffix}`, p.metrics.layerLine, `Findings: ${p.metrics.findingCount} | Recommendations: ${p.metrics.recommendationCount}`);
|
|
13
16
|
}
|
|
14
17
|
if (p.keyPoints.length > 0) {
|
|
15
18
|
lines.push("", "Key points:");
|
|
@@ -69,8 +69,8 @@ export declare const productMessaging: {
|
|
|
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
71
|
readonly exposure: "Reach indicates how prominently affected application paths are surfaced for this upgrade.";
|
|
72
|
-
readonly
|
|
73
|
-
readonly
|
|
72
|
+
readonly prRiskBandsLead: "PR Risk bands (supporting context) read as one of:";
|
|
73
|
+
readonly prRiskBands: readonly string[];
|
|
74
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
|
};
|
|
@@ -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;;;;;;;;;CAYrF,CAAC;AAEX,kFAAkF;AAClF,eAAO,MAAM,gBAAgB;;;;CAOnB,CAAC;AAEX,iEAAiE;AACjE,wBAAgB,wBAAwB,IAAI,MAAM,EAAE,CAOnD"}
|
package/dist/productMessaging.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { PR_RISK_BAND_LABELS } from "./prRiskBand.js";
|
|
2
2
|
import { MERGE_POSTURE_LABEL } from "./riskVocabulary.js";
|
|
3
3
|
/**
|
|
4
4
|
* Canonical marketing / category copy. Operational scan strings stay in scanSurfaceCopy.
|
|
@@ -84,8 +84,8 @@ export const productMessaging = {
|
|
|
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
86
|
exposure: "Reach indicates how prominently affected application paths are surfaced for this upgrade.",
|
|
87
|
-
|
|
88
|
-
|
|
87
|
+
prRiskBandsLead: "PR Risk bands (supporting context) read as one of:",
|
|
88
|
+
prRiskBands: PR_RISK_BAND_LABELS,
|
|
89
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
|
};
|
|
@@ -60,21 +60,21 @@ describe("productMessaging", () => {
|
|
|
60
60
|
expect(productMessaging.hero.h1).not.toContain("Dependabot");
|
|
61
61
|
expect(productMessaging.hero.lead).not.toContain("Dependabot");
|
|
62
62
|
});
|
|
63
|
-
it("describes dashboard posture and
|
|
63
|
+
it("describes dashboard posture and PR Risk bands without scoring jargon", () => {
|
|
64
64
|
const d = productMessaging.dashboardPrCard;
|
|
65
65
|
const text = [
|
|
66
66
|
d.intro,
|
|
67
67
|
d.posture,
|
|
68
68
|
d.exposure,
|
|
69
|
-
d.
|
|
70
|
-
...d.
|
|
69
|
+
d.prRiskBandsLead,
|
|
70
|
+
...d.prRiskBands,
|
|
71
71
|
d.cardBody,
|
|
72
72
|
].join(" ");
|
|
73
73
|
expect(text).toContain("merge recommendation");
|
|
74
74
|
expect(text).toContain("affected application paths");
|
|
75
75
|
expect(text).not.toMatch(/total score|0-100|formula|weight/i);
|
|
76
|
-
expect(d.
|
|
77
|
-
expect(d.
|
|
76
|
+
expect(d.prRiskBands).toHaveLength(5);
|
|
77
|
+
expect(d.prRiskBands).toContain("Medium");
|
|
78
78
|
});
|
|
79
79
|
});
|
|
80
80
|
function collectMarketingStrings() {
|
|
@@ -92,6 +92,6 @@ function collectMarketingStrings() {
|
|
|
92
92
|
out.push(body);
|
|
93
93
|
}
|
|
94
94
|
const d = productMessaging.dashboardPrCard;
|
|
95
|
-
out.push(d.intro, d.posture, d.exposure, d.
|
|
95
|
+
out.push(d.intro, d.posture, d.exposure, d.prRiskBandsLead, d.cardBody, ...d.prRiskBands);
|
|
96
96
|
return out;
|
|
97
97
|
}
|
|
@@ -2,13 +2,14 @@ export type ScanPipelineStatus = "queued" | "running" | "done" | "failed";
|
|
|
2
2
|
export type PipelineCompletionEvidence = {
|
|
3
3
|
scannedAt?: string | null;
|
|
4
4
|
decision?: string | null;
|
|
5
|
-
|
|
5
|
+
/** Denormalized or resolved PR risk score — completion signal only. */
|
|
6
|
+
prRiskScore?: number | null;
|
|
6
7
|
hasResult?: boolean;
|
|
7
8
|
};
|
|
8
|
-
/** Scan completion signals — decision/
|
|
9
|
+
/** Scan completion signals — decision/prRiskScore/result are set after analysis. */
|
|
9
10
|
export declare function hasScanCompletionEvidence(evidence: PipelineCompletionEvidence): boolean;
|
|
10
11
|
/**
|
|
11
|
-
* Resolve wire status using completion evidence (decision,
|
|
12
|
+
* Resolve wire status using completion evidence (decision, prRiskScore, result).
|
|
12
13
|
* Handles races where denormalized columns are written before status flips to done.
|
|
13
14
|
*/
|
|
14
15
|
export declare function resolvePipelineStatus(status: string | undefined, evidence: PipelineCompletionEvidence): ScanPipelineStatus;
|
|
@@ -1 +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,
|
|
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,uEAAuE;IACvE,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB,CAAC;AAsBF,oFAAoF;AACpF,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"}
|
|
@@ -10,13 +10,13 @@ function normalizePipelineStatus(status) {
|
|
|
10
10
|
function isMergePostureDecision(decision) {
|
|
11
11
|
return (decision === "safe" || decision === "needs_review" || decision === "risky");
|
|
12
12
|
}
|
|
13
|
-
/** Scan completion signals — decision/
|
|
13
|
+
/** Scan completion signals — decision/prRiskScore/result are set after analysis. */
|
|
14
14
|
export function hasScanCompletionEvidence(evidence) {
|
|
15
15
|
if (isMergePostureDecision(evidence.decision))
|
|
16
16
|
return true;
|
|
17
17
|
if (evidence.hasResult === true)
|
|
18
18
|
return true;
|
|
19
|
-
if (evidence.
|
|
19
|
+
if (evidence.prRiskScore != null && Number.isFinite(evidence.prRiskScore)) {
|
|
20
20
|
return true;
|
|
21
21
|
}
|
|
22
22
|
if (evidence.scannedAt?.trim())
|
|
@@ -24,7 +24,7 @@ export function hasScanCompletionEvidence(evidence) {
|
|
|
24
24
|
return false;
|
|
25
25
|
}
|
|
26
26
|
/**
|
|
27
|
-
* Resolve wire status using completion evidence (decision,
|
|
27
|
+
* Resolve wire status using completion evidence (decision, prRiskScore, result).
|
|
28
28
|
* Handles races where denormalized columns are written before status flips to done.
|
|
29
29
|
*/
|
|
30
30
|
export function resolvePipelineStatus(status, evidence) {
|
package/dist/riskSignals.d.ts
CHANGED
|
@@ -1,19 +1,19 @@
|
|
|
1
|
-
import { type
|
|
1
|
+
import { type PrRiskBand } from "./prRiskBand.js";
|
|
2
2
|
import type { ScanResult, ScoreLayer } from "./types.js";
|
|
3
3
|
export type RiskSignalLayer = {
|
|
4
4
|
layer: ScoreLayer;
|
|
5
5
|
score: number;
|
|
6
|
-
|
|
6
|
+
band: PrRiskBand;
|
|
7
7
|
};
|
|
8
|
-
/** Canonical
|
|
8
|
+
/** Canonical PR Risk classification for prRisk.score and layer scores. */
|
|
9
9
|
export type RiskSignals = {
|
|
10
10
|
riskIndex: number | null;
|
|
11
|
-
|
|
11
|
+
band: PrRiskBand | null;
|
|
12
12
|
layers: RiskSignalLayer[];
|
|
13
13
|
};
|
|
14
14
|
/**
|
|
15
|
-
* Single owner for
|
|
16
|
-
* Surfaces must consume `facts.riskSignals`
|
|
15
|
+
* Single owner for PR risk index + band classification.
|
|
16
|
+
* Surfaces must consume `facts.riskSignals` — do not re-derive bands.
|
|
17
17
|
*/
|
|
18
18
|
export declare function deriveRiskSignals(result: ScanResult): RiskSignals | null;
|
|
19
19
|
//# sourceMappingURL=riskSignals.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"riskSignals.d.ts","sourceRoot":"","sources":["../src/riskSignals.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"riskSignals.d.ts","sourceRoot":"","sources":["../src/riskSignals.ts"],"names":[],"mappings":"AAAA,OAAO,EAAe,KAAK,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAE/D,OAAO,KAAK,EAAe,UAAU,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAEtE,MAAM,MAAM,eAAe,GAAG;IAC5B,KAAK,EAAE,UAAU,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,UAAU,CAAC;CAClB,CAAC;AAEF,0EAA0E;AAC1E,MAAM,MAAM,WAAW,GAAG;IACxB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,IAAI,EAAE,UAAU,GAAG,IAAI,CAAC;IACxB,MAAM,EAAE,eAAe,EAAE,CAAC;CAC3B,CAAC;AASF;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,UAAU,GAAG,WAAW,GAAG,IAAI,CAqBxE"}
|
package/dist/riskSignals.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { scoreToBand } from "./prRiskBand.js";
|
|
2
|
+
import { resolvePrRiskLayerScores, resolvePrRiskScore } from "./prRiskWire.js";
|
|
2
3
|
const LAYER_ORDER = [
|
|
3
4
|
"security",
|
|
4
5
|
"maintainability",
|
|
@@ -6,27 +7,25 @@ const LAYER_ORDER = [
|
|
|
6
7
|
"upgradeImpact",
|
|
7
8
|
];
|
|
8
9
|
/**
|
|
9
|
-
* Single owner for
|
|
10
|
-
* Surfaces must consume `facts.riskSignals`
|
|
10
|
+
* Single owner for PR risk index + band classification.
|
|
11
|
+
* Surfaces must consume `facts.riskSignals` — do not re-derive bands.
|
|
11
12
|
*/
|
|
12
13
|
export function deriveRiskSignals(result) {
|
|
13
|
-
const riskIndex =
|
|
14
|
-
|
|
15
|
-
: null;
|
|
16
|
-
const layerScores = result.layerScores;
|
|
14
|
+
const riskIndex = resolvePrRiskScore(result);
|
|
15
|
+
const layerScores = resolvePrRiskLayerScores(result);
|
|
17
16
|
if (riskIndex == null && layerScores == null) {
|
|
18
17
|
return null;
|
|
19
18
|
}
|
|
20
|
-
const
|
|
19
|
+
const band = scoreToBand(riskIndex);
|
|
21
20
|
const layers = layerScores
|
|
22
21
|
? LAYER_ORDER.map((layer) => {
|
|
23
22
|
const score = layerScores[layer];
|
|
24
23
|
return {
|
|
25
24
|
layer,
|
|
26
25
|
score,
|
|
27
|
-
|
|
26
|
+
band: scoreToBand(score) ?? "very_low",
|
|
28
27
|
};
|
|
29
28
|
})
|
|
30
29
|
: [];
|
|
31
|
-
return { riskIndex,
|
|
30
|
+
return { riskIndex, band, layers };
|
|
32
31
|
}
|
package/dist/riskVocabulary.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { prRiskBandAriaFragment } from "./prRiskBand.js";
|
|
2
2
|
/** Canonical display strings for merge posture values. */
|
|
3
3
|
export const MERGE_POSTURE_LABEL = {
|
|
4
4
|
safe: "Safe",
|
|
@@ -44,17 +44,17 @@ export function mergePostureLabel(decision, fallback = "-") {
|
|
|
44
44
|
*/
|
|
45
45
|
export function ariaLabelForPosture(decision, score) {
|
|
46
46
|
const label = mergePostureLabel(decision);
|
|
47
|
-
const
|
|
48
|
-
if (
|
|
49
|
-
return `${label}, ${
|
|
47
|
+
const bandFragment = prRiskBandAriaFragment(score);
|
|
48
|
+
if (bandFragment)
|
|
49
|
+
return `${label}, ${bandFragment}`;
|
|
50
50
|
return label;
|
|
51
51
|
}
|
|
52
52
|
/** Accessible label for unified PR card findings block. */
|
|
53
53
|
export function ariaLabelForCardSummary(postureLabel, riskIndex, observations, supportingLine) {
|
|
54
54
|
const parts = [postureLabel];
|
|
55
|
-
const
|
|
56
|
-
if (
|
|
57
|
-
parts.push(
|
|
55
|
+
const bandFragment = prRiskBandAriaFragment(riskIndex);
|
|
56
|
+
if (bandFragment)
|
|
57
|
+
parts.push(bandFragment);
|
|
58
58
|
for (const obs of observations ?? []) {
|
|
59
59
|
if (obs?.trim())
|
|
60
60
|
parts.push(obs.trim());
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { describe, expect, it } from "vitest";
|
|
2
|
-
import {
|
|
2
|
+
import { scoreToBand } from "./prRiskBand.js";
|
|
3
3
|
import { buildScanPresentationBundle } from "./presentation/orchestration/buildScanPresentationBundle.js";
|
|
4
4
|
import { scanResultBullmq, scanResultEslint, scanResultFastifyRuntime, scanResultLimitedContext, scanResultMixedTypescriptFastify, scanResultPrettier, scanResultTypescriptPatch, scanResultVitest, } from "./presentation/fixtures/presentationPersonaFixtures.js";
|
|
5
5
|
const validationPersonas = [
|
|
@@ -42,7 +42,7 @@ describe("scanPresentationBundle golden — proof model", () => {
|
|
|
42
42
|
expect(apiArea?.hotspotPackages).toContain("fastify");
|
|
43
43
|
expect(apiArea?.verificationFocus.length).toBeGreaterThan(0);
|
|
44
44
|
expect(facts.riskSignals?.riskIndex).toBe(55);
|
|
45
|
-
expect(facts.riskSignals?.
|
|
45
|
+
expect(facts.riskSignals?.band).toBe(scoreToBand(55));
|
|
46
46
|
expect(facts.riskIndex).toBe(facts.riskSignals?.riskIndex);
|
|
47
47
|
});
|
|
48
48
|
it("limited-context — diagnostics without synthetic confidence", () => {
|
|
@@ -59,7 +59,7 @@ describe("scanPresentationBundle golden — proof model", () => {
|
|
|
59
59
|
expect(facts.availability.corpusGateReason).toBe("ok");
|
|
60
60
|
expect(facts.packageSemantics?.dependencyClass).toBe("tooling");
|
|
61
61
|
expect(facts.riskSignals?.riskIndex).toBe(18);
|
|
62
|
-
expect(facts.riskSignals?.
|
|
62
|
+
expect(facts.riskSignals?.band).toBe(scoreToBand(18));
|
|
63
63
|
});
|
|
64
64
|
it("affected areas always carry linkage arrays (structure)", () => {
|
|
65
65
|
for (const { result } of validationPersonas) {
|
|
@@ -3,7 +3,12 @@ import type { EngineEmittedScanResult, ScanResult } from "./types.js";
|
|
|
3
3
|
/** Bump when persisted `result` JSON validation rules change materially (relaxed / legacy-tolerant). */
|
|
4
4
|
export declare const SCAN_RESULT_ABI: "2";
|
|
5
5
|
/** Bump when strict fresh-engine-output validation rules change materially. */
|
|
6
|
-
export declare const ENGINE_OUTPUT_SCAN_ABI: "
|
|
6
|
+
export declare const ENGINE_OUTPUT_SCAN_ABI: "4";
|
|
7
|
+
/**
|
|
8
|
+
* Synthesize ABI-4 prRisk/repositoryHealth from legacy totalScore when an engine
|
|
9
|
+
* has not yet adopted the dual-score wire (transitional bridge).
|
|
10
|
+
*/
|
|
11
|
+
export declare function normalizeEngineOutputAbi4(raw: unknown): unknown;
|
|
7
12
|
/**
|
|
8
13
|
* Minimum structural invariants for **persisted** `scans.result` JSON and legacy reads.
|
|
9
14
|
* `methodologyVersion` stays optional so historical rows without it remain valid.
|
|
@@ -17,6 +22,24 @@ export declare const scanResultSchema: z.ZodObject<{
|
|
|
17
22
|
ecosystem: z.ZodNumber;
|
|
18
23
|
upgradeImpact: z.ZodNumber;
|
|
19
24
|
}, z.core.$strip>;
|
|
25
|
+
prRisk: z.ZodOptional<z.ZodObject<{
|
|
26
|
+
score: z.ZodNumber;
|
|
27
|
+
layerScores: z.ZodOptional<z.ZodObject<{
|
|
28
|
+
security: z.ZodNumber;
|
|
29
|
+
maintainability: z.ZodNumber;
|
|
30
|
+
ecosystem: z.ZodNumber;
|
|
31
|
+
upgradeImpact: z.ZodNumber;
|
|
32
|
+
}, z.core.$strip>>;
|
|
33
|
+
}, z.core.$strip>>;
|
|
34
|
+
repositoryHealth: z.ZodOptional<z.ZodObject<{
|
|
35
|
+
totalScore: z.ZodNumber;
|
|
36
|
+
layerScores: z.ZodOptional<z.ZodObject<{
|
|
37
|
+
security: z.ZodNumber;
|
|
38
|
+
maintainability: z.ZodNumber;
|
|
39
|
+
ecosystem: z.ZodNumber;
|
|
40
|
+
upgradeImpact: z.ZodNumber;
|
|
41
|
+
}, z.core.$strip>>;
|
|
42
|
+
}, z.core.$strip>>;
|
|
20
43
|
findings: z.ZodPipe<z.ZodOptional<z.ZodUnion<readonly [z.ZodArray<z.ZodUnknown>, z.ZodNull]>>, z.ZodTransform<unknown[], unknown[] | null | undefined>>;
|
|
21
44
|
methodologyVersion: z.ZodOptional<z.ZodString>;
|
|
22
45
|
confidence: z.ZodOptional<z.ZodEnum<{
|
|
@@ -210,6 +233,24 @@ export declare const engineOutputScanResultSchema: z.ZodObject<{
|
|
|
210
233
|
}>;
|
|
211
234
|
}, z.core.$strip>;
|
|
212
235
|
}, z.core.$strip>;
|
|
236
|
+
prRisk: z.ZodObject<{
|
|
237
|
+
score: z.ZodNumber;
|
|
238
|
+
layerScores: z.ZodOptional<z.ZodObject<{
|
|
239
|
+
security: z.ZodNumber;
|
|
240
|
+
maintainability: z.ZodNumber;
|
|
241
|
+
ecosystem: z.ZodNumber;
|
|
242
|
+
upgradeImpact: z.ZodNumber;
|
|
243
|
+
}, z.core.$strip>>;
|
|
244
|
+
}, z.core.$strip>;
|
|
245
|
+
repositoryHealth: z.ZodObject<{
|
|
246
|
+
totalScore: z.ZodNumber;
|
|
247
|
+
layerScores: z.ZodOptional<z.ZodObject<{
|
|
248
|
+
security: z.ZodNumber;
|
|
249
|
+
maintainability: z.ZodNumber;
|
|
250
|
+
ecosystem: z.ZodNumber;
|
|
251
|
+
upgradeImpact: z.ZodNumber;
|
|
252
|
+
}, z.core.$strip>>;
|
|
253
|
+
}, z.core.$strip>;
|
|
213
254
|
}, z.core.$loose>;
|
|
214
255
|
export type EngineOutputScanResultParseFailure = {
|
|
215
256
|
ok: false;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scanResultSchema.d.ts","sourceRoot":"","sources":["../src/scanResultSchema.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,uBAAuB,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAEtE,wGAAwG;AACxG,eAAO,MAAM,eAAe,EAAG,GAAY,CAAC;AAE5C,+EAA+E;AAC/E,eAAO,MAAM,sBAAsB,EAAG,GAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"scanResultSchema.d.ts","sourceRoot":"","sources":["../src/scanResultSchema.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,uBAAuB,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAEtE,wGAAwG;AACxG,eAAO,MAAM,eAAe,EAAG,GAAY,CAAC;AAE5C,+EAA+E;AAC/E,eAAO,MAAM,sBAAsB,EAAG,GAAY,CAAC;AAmBnD;;;GAGG;AACH,wBAAgB,yBAAyB,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAc/D;AAED;;;;GAIG;AACH,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBA8Bb,CAAC;AAUjB;;;GAGG;AACH,eAAO,MAAM,4BAA4B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAMvC,CAAC;AAEH,MAAM,MAAM,kCAAkC,GAAG;IAC/C,EAAE,EAAE,KAAK,CAAC;IACV,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,kCAAkC,GAAG;IAC/C,EAAE,EAAE,IAAI,CAAC;IACT,MAAM,EAAE,uBAAuB,CAAC;CACjC,CAAC;AAEF,wBAAgB,+BAA+B,CAC7C,IAAI,EAAE,OAAO,GACZ,kCAAkC,GAAG,kCAAkC,CAezE;AAED,uFAAuF;AACvF,wBAAgB,kCAAkC,CAChD,IAAI,EAAE,OAAO,GACZ,uBAAuB,CAMzB;AAED,MAAM,MAAM,sBAAsB,GAAG;IACnC,EAAE,EAAE,KAAK,CAAC;IACV,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,sBAAsB,GAAG;IACnC,EAAE,EAAE,IAAI,CAAC;IACT,MAAM,EAAE,UAAU,CAAC;CACpB,CAAC;AAEF,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,OAAO,GACZ,sBAAsB,GAAG,sBAAsB,CAajD;AAED,yEAAyE;AACzE,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,OAAO,GAAG,UAAU,CAMhE"}
|
package/dist/scanResultSchema.js
CHANGED
|
@@ -3,13 +3,42 @@ import { z } from "zod";
|
|
|
3
3
|
/** Bump when persisted `result` JSON validation rules change materially (relaxed / legacy-tolerant). */
|
|
4
4
|
export const SCAN_RESULT_ABI = "2";
|
|
5
5
|
/** Bump when strict fresh-engine-output validation rules change materially. */
|
|
6
|
-
export const ENGINE_OUTPUT_SCAN_ABI = "
|
|
6
|
+
export const ENGINE_OUTPUT_SCAN_ABI = "4";
|
|
7
7
|
const layerScoresSchema = z.object({
|
|
8
8
|
security: z.number(),
|
|
9
9
|
maintainability: z.number(),
|
|
10
10
|
ecosystem: z.number(),
|
|
11
11
|
upgradeImpact: z.number(),
|
|
12
12
|
});
|
|
13
|
+
const prRiskSchema = z.object({
|
|
14
|
+
score: z.number().min(0).max(100),
|
|
15
|
+
layerScores: layerScoresSchema.optional(),
|
|
16
|
+
});
|
|
17
|
+
const repositoryHealthSchema = z.object({
|
|
18
|
+
totalScore: z.number().min(0).max(100),
|
|
19
|
+
layerScores: layerScoresSchema.optional(),
|
|
20
|
+
});
|
|
21
|
+
/**
|
|
22
|
+
* Synthesize ABI-4 prRisk/repositoryHealth from legacy totalScore when an engine
|
|
23
|
+
* has not yet adopted the dual-score wire (transitional bridge).
|
|
24
|
+
*/
|
|
25
|
+
export function normalizeEngineOutputAbi4(raw) {
|
|
26
|
+
if (!raw || typeof raw !== "object")
|
|
27
|
+
return raw;
|
|
28
|
+
const obj = raw;
|
|
29
|
+
const totalScore = obj.totalScore;
|
|
30
|
+
const layerScores = obj.layerScores;
|
|
31
|
+
if (typeof totalScore !== "number" || !Number.isFinite(totalScore)) {
|
|
32
|
+
return raw;
|
|
33
|
+
}
|
|
34
|
+
if (!layerScores || typeof layerScores !== "object")
|
|
35
|
+
return raw;
|
|
36
|
+
return {
|
|
37
|
+
...obj,
|
|
38
|
+
prRisk: obj.prRisk ?? { score: totalScore, layerScores },
|
|
39
|
+
repositoryHealth: obj.repositoryHealth ?? { totalScore, layerScores },
|
|
40
|
+
};
|
|
41
|
+
}
|
|
13
42
|
/**
|
|
14
43
|
* Minimum structural invariants for **persisted** `scans.result` JSON and legacy reads.
|
|
15
44
|
* `methodologyVersion` stays optional so historical rows without it remain valid.
|
|
@@ -19,6 +48,8 @@ export const scanResultSchema = z
|
|
|
19
48
|
.object({
|
|
20
49
|
totalScore: z.number().min(0).max(100),
|
|
21
50
|
layerScores: layerScoresSchema,
|
|
51
|
+
prRisk: prRiskSchema.optional(),
|
|
52
|
+
repositoryHealth: repositoryHealthSchema.optional(),
|
|
22
53
|
findings: z
|
|
23
54
|
.union([z.array(z.unknown()), z.null()])
|
|
24
55
|
.optional()
|
|
@@ -59,9 +90,11 @@ export const engineOutputScanResultSchema = scanResultSchema.extend({
|
|
|
59
90
|
methodologyVersion: z.string().trim().min(1),
|
|
60
91
|
generatedAt: engineOutputGeneratedAtSchema,
|
|
61
92
|
assessment: assessmentSchema,
|
|
93
|
+
prRisk: prRiskSchema,
|
|
94
|
+
repositoryHealth: repositoryHealthSchema,
|
|
62
95
|
});
|
|
63
96
|
export function safeParseEngineOutputScanResult(data) {
|
|
64
|
-
const parsed = engineOutputScanResultSchema.safeParse(data);
|
|
97
|
+
const parsed = engineOutputScanResultSchema.safeParse(normalizeEngineOutputAbi4(data));
|
|
65
98
|
if (!parsed.success) {
|
|
66
99
|
const issues = parsed.error.issues.map((i) => `${i.path.join(".") || "(root)"}: ${i.message}`);
|
|
67
100
|
return {
|