@mergesignal/shared 0.12.0 → 0.12.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/deriveScanNarrative.d.ts.map +1 -1
- package/dist/deriveScanNarrative.js +4 -0
- package/dist/formatInsight.d.ts +3 -3
- package/dist/formatInsight.d.ts.map +1 -1
- package/dist/formatInsight.js +0 -9
- package/dist/index.d.ts +0 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +0 -3
- package/dist/prRiskBand.d.ts +7 -0
- package/dist/prRiskBand.d.ts.map +1 -1
- package/dist/prRiskBand.js +12 -0
- package/dist/prRiskBand.test.js +12 -1
- package/dist/presentation/abi3Expression.test.js +46 -0
- package/dist/presentation/bundleAccessorParity.test.d.ts +9 -0
- package/dist/presentation/bundleAccessorParity.test.d.ts.map +1 -0
- package/dist/presentation/bundleAccessorParity.test.js +126 -0
- package/dist/presentation/cliParity.test.d.ts +2 -0
- package/dist/presentation/cliParity.test.d.ts.map +1 -0
- package/dist/presentation/cliParity.test.js +49 -0
- package/dist/presentation/compose/narrativeCompose.d.ts +0 -4
- package/dist/presentation/compose/narrativeCompose.d.ts.map +1 -1
- package/dist/presentation/compose/narrativeCompose.js +0 -20
- package/dist/presentation/decisionSurface.test.d.ts +2 -0
- package/dist/presentation/decisionSurface.test.d.ts.map +1 -0
- package/dist/presentation/decisionSurface.test.js +290 -0
- package/dist/presentation/dto/assessmentPresentationFields.d.ts +4 -0
- package/dist/presentation/dto/assessmentPresentationFields.d.ts.map +1 -1
- package/dist/presentation/index.d.ts +1 -1
- package/dist/presentation/index.d.ts.map +1 -1
- package/dist/presentation/index.js +1 -1
- package/dist/presentation/orchestration/buildScanPresentationBundle.d.ts +1 -0
- package/dist/presentation/orchestration/buildScanPresentationBundle.d.ts.map +1 -1
- package/dist/presentation/orchestration/buildScanPresentationBundle.js +4 -1
- package/dist/presentation/orchestration/scanPresentationBundle.d.ts +4 -4
- package/dist/presentation/orchestration/scanPresentationBundle.d.ts.map +1 -1
- package/dist/presentation/presenters/presentCliScanSummary.d.ts.map +1 -1
- package/dist/presentation/presenters/presentCliScanSummary.js +9 -7
- package/dist/presentation/presenters/presentGitHubCheckRun.d.ts.map +1 -1
- package/dist/presentation/presenters/presentGitHubCheckRun.js +11 -12
- package/dist/presentation/presenters/presentGitHubPrComment.d.ts.map +1 -1
- package/dist/presentation/presenters/presentGitHubPrComment.js +11 -10
- package/dist/presentation/presenters/presentScanDetails.d.ts.map +1 -1
- package/dist/presentation/presenters/presentScanDetails.js +8 -11
- package/dist/presentation/projectAssessmentFields.d.ts.map +1 -1
- package/dist/presentation/projectAssessmentFields.js +6 -0
- package/dist/presentation/surfaceParity.test.js +8 -0
- package/dist/scanResultSchema.d.ts +158 -0
- package/dist/scanResultSchema.d.ts.map +1 -1
- package/package.json +1 -1
- package/dist/scanDetailViewModelTypes.d.ts +0 -159
- package/dist/scanDetailViewModelTypes.d.ts.map +0 -1
- package/dist/scanDetailViewModelTypes.js +0 -4
- package/dist/truncateCardSummary.d.ts +0 -5
- package/dist/truncateCardSummary.d.ts.map +0 -1
- package/dist/truncateCardSummary.js +0 -23
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"deriveScanNarrative.d.ts","sourceRoot":"","sources":["../src/deriveScanNarrative.ts"],"names":[],"mappings":"AAYA,OAAO,EAgBL,KAAK,kBAAkB,EACxB,MAAM,yBAAyB,CAAC;AAGjC,OAAO,KAAK,EAMV,UAAU,EACX,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"deriveScanNarrative.d.ts","sourceRoot":"","sources":["../src/deriveScanNarrative.ts"],"names":[],"mappings":"AAYA,OAAO,EAgBL,KAAK,kBAAkB,EACxB,MAAM,yBAAyB,CAAC;AAGjC,OAAO,KAAK,EAMV,UAAU,EACX,MAAM,YAAY,CAAC;AAwiBpB;;GAEG;AACH,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,UAAU,GAAG,IAAI,GAAG,SAAS,GACpC,kBAAkB,CAsIpB"}
|
|
@@ -304,6 +304,10 @@ function guidanceFromRecommendation(rec) {
|
|
|
304
304
|
remediation: rec.impact,
|
|
305
305
|
};
|
|
306
306
|
}
|
|
307
|
+
/**
|
|
308
|
+
* Legacy insight/finding/recommendation synthesis for narrative availability tiers.
|
|
309
|
+
* Not presentation authority — shared surfaces use assessment expression fields instead.
|
|
310
|
+
*/
|
|
307
311
|
function collectReviewerGuidance(result) {
|
|
308
312
|
const guidance = [];
|
|
309
313
|
const insights = Array.isArray(result.insights) ? result.insights : [];
|
package/dist/formatInsight.d.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import type { PRInsight, PRDecision
|
|
2
|
-
|
|
1
|
+
import type { PRInsight, PRDecision } from "./types.js";
|
|
2
|
+
type FormattedInsight = {
|
|
3
3
|
message: string;
|
|
4
4
|
where: string;
|
|
5
5
|
action: string;
|
|
6
6
|
};
|
|
7
|
-
export declare function decisionTitle(recommendation: PRDecisionRecommendation): string;
|
|
8
7
|
export declare function formatInsight(insight: PRInsight): FormattedInsight;
|
|
9
8
|
/** Legacy markdown renderer for raw PR insights (format-only; no bundle inference). */
|
|
10
9
|
export declare function renderInsightsAsMarkdown(insights: PRInsight[], decision: PRDecision): string;
|
|
10
|
+
export {};
|
|
11
11
|
//# sourceMappingURL=formatInsight.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"formatInsight.d.ts","sourceRoot":"","sources":["../src/formatInsight.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"formatInsight.d.ts","sourceRoot":"","sources":["../src/formatInsight.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAGxD,KAAK,gBAAgB,GAAG;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAgBF,wBAAgB,aAAa,CAAC,OAAO,EAAE,SAAS,GAAG,gBAAgB,CAMlE;AA+BD,uFAAuF;AACvF,wBAAgB,wBAAwB,CACtC,QAAQ,EAAE,SAAS,EAAE,EACrB,QAAQ,EAAE,UAAU,GACnB,MAAM,CAUR"}
|
package/dist/formatInsight.js
CHANGED
|
@@ -1,13 +1,4 @@
|
|
|
1
1
|
import { MERGE_POSTURE_LABEL } from "./riskVocabulary.js";
|
|
2
|
-
const DECISION_TITLES = {
|
|
3
|
-
safe: "No significant dependency risks detected",
|
|
4
|
-
needs_review: "Elevated dependency merge risk",
|
|
5
|
-
risky: "Merge blocked - critical dependency risk",
|
|
6
|
-
};
|
|
7
|
-
// Title rendered once per PR comment, not per insight
|
|
8
|
-
export function decisionTitle(recommendation) {
|
|
9
|
-
return DECISION_TITLES[recommendation];
|
|
10
|
-
}
|
|
11
2
|
/**
|
|
12
3
|
* Normalizes typographic punctuation to ASCII equivalents so that LLM output
|
|
13
4
|
* renders consistently across PR comments, the web UI, and CLI output.
|
package/dist/index.d.ts
CHANGED
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
export * from "./types.js";
|
|
2
2
|
export * from "./assessmentLabels.js";
|
|
3
3
|
export * from "./assessmentProjection.js";
|
|
4
|
-
export * from "./formatInsight.js";
|
|
5
4
|
export * from "./riskVocabulary.js";
|
|
6
5
|
export * from "./selectTopAffectedAreas.js";
|
|
7
6
|
export * from "./cardSummaryCopy.js";
|
|
8
|
-
export * from "./truncateCardSummary.js";
|
|
9
7
|
export * from "./formatCardAreaLabels.js";
|
|
10
8
|
export * from "./prRiskBand.js";
|
|
11
9
|
export * from "./prRiskWire.js";
|
|
@@ -20,7 +18,6 @@ export * from "./extractRepositoryContextFacts.js";
|
|
|
20
18
|
export * from "./narrativePresentation.js";
|
|
21
19
|
export * from "./normalizeGeneratedText.js";
|
|
22
20
|
export { presentGitHubPrCommentMarkdownFromResult } from "./presentGitHubPrComment.js";
|
|
23
|
-
export * from "./scanDetailViewModelTypes.js";
|
|
24
21
|
export * from "./scanCardPresentationState.js";
|
|
25
22
|
export * from "./scanResultSchema.js";
|
|
26
23
|
export * from "./scanSurfaceCopy.js";
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,uBAAuB,CAAC;AACtC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,uBAAuB,CAAC;AACtC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,qBAAqB,CAAC;AACpC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,sBAAsB,CAAC;AACrC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,iBAAiB,CAAC;AAChC,cAAc,iBAAiB,CAAC;AAChC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,yBAAyB,CAAC;AACxC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,8BAA8B,CAAC;AAC7C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,iCAAiC,CAAC;AAChD,cAAc,0BAA0B,CAAC;AACzC,cAAc,oCAAoC,CAAC;AACnD,cAAc,4BAA4B,CAAC;AAC3C,cAAc,6BAA6B,CAAC;AAC5C,OAAO,EAAE,wCAAwC,EAAE,MAAM,6BAA6B,CAAC;AACvF,cAAc,gCAAgC,CAAC;AAC/C,cAAc,uBAAuB,CAAC;AACtC,cAAc,sBAAsB,CAAC;AACrC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,wBAAwB,CAAC;AACvC,cAAc,yBAAyB,CAAC;AACxC,cAAc,uBAAuB,CAAC;AACtC,cAAc,yBAAyB,CAAC;AACxC,OAAO,EACL,eAAe,EACf,sBAAsB,EACtB,qBAAqB,EACrB,wBAAwB,EACxB,uBAAuB,EACvB,aAAa,EACb,oBAAoB,EACpB,mBAAmB,GACpB,MAAM,uCAAuC,CAAC;AAC/C,OAAO,EACL,cAAc,EACd,yBAAyB,GAC1B,MAAM,kCAAkC,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
export * from "./types.js";
|
|
2
2
|
export * from "./assessmentLabels.js";
|
|
3
3
|
export * from "./assessmentProjection.js";
|
|
4
|
-
export * from "./formatInsight.js";
|
|
5
4
|
export * from "./riskVocabulary.js";
|
|
6
5
|
export * from "./selectTopAffectedAreas.js";
|
|
7
6
|
export * from "./cardSummaryCopy.js";
|
|
8
|
-
export * from "./truncateCardSummary.js";
|
|
9
7
|
export * from "./formatCardAreaLabels.js";
|
|
10
8
|
export * from "./prRiskBand.js";
|
|
11
9
|
export * from "./prRiskWire.js";
|
|
@@ -20,7 +18,6 @@ export * from "./extractRepositoryContextFacts.js";
|
|
|
20
18
|
export * from "./narrativePresentation.js";
|
|
21
19
|
export * from "./normalizeGeneratedText.js";
|
|
22
20
|
export { presentGitHubPrCommentMarkdownFromResult } from "./presentGitHubPrComment.js";
|
|
23
|
-
export * from "./scanDetailViewModelTypes.js";
|
|
24
21
|
export * from "./scanCardPresentationState.js";
|
|
25
22
|
export * from "./scanResultSchema.js";
|
|
26
23
|
export * from "./scanSurfaceCopy.js";
|
package/dist/prRiskBand.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { ScanNarrativeFacts } from "./scanNarrativeFacts.js";
|
|
1
2
|
/**
|
|
2
3
|
* Canonical PR Risk band contract — sole authority for PR Risk band derivation.
|
|
3
4
|
* Independent from legacy exposure presentation and merge verdict (`assessment.posture`).
|
|
@@ -18,6 +19,12 @@ export declare function scoreToBandLabel(score: number | null | undefined): stri
|
|
|
18
19
|
export declare function prRiskBandLabel(band: PrRiskBand): string;
|
|
19
20
|
/** Fragment for composite aria labels on PR surfaces. */
|
|
20
21
|
export declare function prRiskBandAriaFragment(score: number | null | undefined): string | null;
|
|
22
|
+
export type PrRiskSummary = {
|
|
23
|
+
prRiskScore: number;
|
|
24
|
+
prRiskBandLabel: string;
|
|
25
|
+
};
|
|
26
|
+
/** Format PR Risk score + band from narrative facts (not assessment projection). */
|
|
27
|
+
export declare function formatPrRiskSummary(facts: Pick<ScanNarrativeFacts, "riskSignals" | "riskIndex">): PrRiskSummary | undefined;
|
|
21
28
|
/** Project 5-band PR Risk to 3-bucket scan-detail gauge band. */
|
|
22
29
|
export declare function prRiskBandToGaugeBand(band: PrRiskBand): PrRiskGaugeBand;
|
|
23
30
|
//# sourceMappingURL=prRiskBand.d.ts.map
|
package/dist/prRiskBand.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prRiskBand.d.ts","sourceRoot":"","sources":["../src/prRiskBand.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,eAAO,MAAM,gBAAgB,EAAG,GAAY,CAAC;AAE7C,iEAAiE;AACjE,eAAO,MAAM,uBAAuB,gCAAiC,CAAC;AAEtE,MAAM,MAAM,UAAU,GAAG,UAAU,GAAG,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,UAAU,CAAC;AAU7E,oDAAoD;AACpD,eAAO,MAAM,mBAAmB,EAAE,SAAS,MAAM,EAMhD,CAAC;AAUF,mEAAmE;AACnE,MAAM,MAAM,eAAe,GAAG,KAAK,GAAG,UAAU,GAAG,MAAM,CAAC;AAO1D,wDAAwD;AACxD,wBAAgB,WAAW,CACzB,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAC/B,UAAU,GAAG,IAAI,CAKnB;AAED,+EAA+E;AAC/E,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAC/B,MAAM,GAAG,IAAI,CAGf;AAED,yCAAyC;AACzC,wBAAgB,eAAe,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM,CAExD;AAED,yDAAyD;AACzD,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAC/B,MAAM,GAAG,IAAI,CAIf;AAED,iEAAiE;AACjE,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,UAAU,GAAG,eAAe,CAIvE"}
|
|
1
|
+
{"version":3,"file":"prRiskBand.d.ts","sourceRoot":"","sources":["../src/prRiskBand.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAElE;;;GAGG;AAEH,eAAO,MAAM,gBAAgB,EAAG,GAAY,CAAC;AAE7C,iEAAiE;AACjE,eAAO,MAAM,uBAAuB,gCAAiC,CAAC;AAEtE,MAAM,MAAM,UAAU,GAAG,UAAU,GAAG,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,UAAU,CAAC;AAU7E,oDAAoD;AACpD,eAAO,MAAM,mBAAmB,EAAE,SAAS,MAAM,EAMhD,CAAC;AAUF,mEAAmE;AACnE,MAAM,MAAM,eAAe,GAAG,KAAK,GAAG,UAAU,GAAG,MAAM,CAAC;AAO1D,wDAAwD;AACxD,wBAAgB,WAAW,CACzB,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAC/B,UAAU,GAAG,IAAI,CAKnB;AAED,+EAA+E;AAC/E,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAC/B,MAAM,GAAG,IAAI,CAGf;AAED,yCAAyC;AACzC,wBAAgB,eAAe,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM,CAExD;AAED,yDAAyD;AACzD,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAC/B,MAAM,GAAG,IAAI,CAIf;AAED,MAAM,MAAM,aAAa,GAAG;IAC1B,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,MAAM,CAAC;CACzB,CAAC;AAEF,oFAAoF;AACpF,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,IAAI,CAAC,kBAAkB,EAAE,aAAa,GAAG,WAAW,CAAC,GAC3D,aAAa,GAAG,SAAS,CAW3B;AAED,iEAAiE;AACjE,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,UAAU,GAAG,eAAe,CAIvE"}
|
package/dist/prRiskBand.js
CHANGED
|
@@ -56,6 +56,18 @@ export function prRiskBandAriaFragment(score) {
|
|
|
56
56
|
return null;
|
|
57
57
|
return `PR Risk: ${label}`;
|
|
58
58
|
}
|
|
59
|
+
/** Format PR Risk score + band from narrative facts (not assessment projection). */
|
|
60
|
+
export function formatPrRiskSummary(facts) {
|
|
61
|
+
const prRiskScore = facts.riskSignals?.riskIndex;
|
|
62
|
+
if (prRiskScore == null || !Number.isFinite(prRiskScore))
|
|
63
|
+
return undefined;
|
|
64
|
+
const prRiskBandLabelText = facts.riskSignals?.band != null
|
|
65
|
+
? prRiskBandLabel(facts.riskSignals.band)
|
|
66
|
+
: scoreToBandLabel(prRiskScore);
|
|
67
|
+
if (!prRiskBandLabelText)
|
|
68
|
+
return undefined;
|
|
69
|
+
return { prRiskScore, prRiskBandLabel: prRiskBandLabelText };
|
|
70
|
+
}
|
|
59
71
|
/** Project 5-band PR Risk to 3-bucket scan-detail gauge band. */
|
|
60
72
|
export function prRiskBandToGaugeBand(band) {
|
|
61
73
|
if (band === "critical" || band === "high")
|
package/dist/prRiskBand.test.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { describe, expect, it } from "vitest";
|
|
2
|
-
import { PR_RISK_BAND_ABI, PR_RISK_BAND_THRESHOLDS, prRiskBandAriaFragment, prRiskBandLabel, prRiskBandToGaugeBand, scoreToBand, scoreToBandLabel, } from "./prRiskBand.js";
|
|
2
|
+
import { PR_RISK_BAND_ABI, PR_RISK_BAND_THRESHOLDS, formatPrRiskSummary, prRiskBandAriaFragment, prRiskBandLabel, prRiskBandToGaugeBand, scoreToBand, scoreToBandLabel, } from "./prRiskBand.js";
|
|
3
3
|
describe("PR_RISK_BAND_ABI", () => {
|
|
4
4
|
it("is stable v1", () => {
|
|
5
5
|
expect(PR_RISK_BAND_ABI).toBe("1");
|
|
@@ -46,6 +46,17 @@ describe("prRiskBandAriaFragment", () => {
|
|
|
46
46
|
expect(prRiskBandAriaFragment(55)).toBe("PR Risk: Medium");
|
|
47
47
|
});
|
|
48
48
|
});
|
|
49
|
+
describe("formatPrRiskSummary", () => {
|
|
50
|
+
it("returns score and band label from riskSignals", () => {
|
|
51
|
+
expect(formatPrRiskSummary({
|
|
52
|
+
riskSignals: { riskIndex: 55, band: "medium", layers: [] },
|
|
53
|
+
riskIndex: 55,
|
|
54
|
+
})).toEqual({ prRiskScore: 55, prRiskBandLabel: "Medium" });
|
|
55
|
+
});
|
|
56
|
+
it("returns undefined when risk index is missing", () => {
|
|
57
|
+
expect(formatPrRiskSummary({ riskSignals: null, riskIndex: null })).toBeUndefined();
|
|
58
|
+
});
|
|
59
|
+
});
|
|
49
60
|
describe("prRiskBandToGaugeBand", () => {
|
|
50
61
|
it("projects to three gauge buckets", () => {
|
|
51
62
|
expect(prRiskBandToGaugeBand("very_low")).toBe("low");
|
|
@@ -13,6 +13,7 @@ import { describe, expect, it } from "vitest";
|
|
|
13
13
|
import { minimalReviewFocalPoint, reachScopeFor, verificationScopeFor, withAssessmentScope, } from "../fixtures/assessmentScopeFixtures.js";
|
|
14
14
|
import { projectReasoningLines, projectVerificationActions, } from "../assessmentProjection.js";
|
|
15
15
|
import { toPublicPresentation } from "../assessmentPresentationUtils.js";
|
|
16
|
+
import { projectAssessmentFields } from "./projectAssessmentFields.js";
|
|
16
17
|
import { buildScanPresentationBundle } from "./orchestration/buildScanPresentationBundle.js";
|
|
17
18
|
import { presentGitHubPrComment } from "./presenters/presentGitHubPrComment.js";
|
|
18
19
|
import { presentGitHubCheckRun } from "./presenters/presentGitHubCheckRun.js";
|
|
@@ -190,6 +191,51 @@ describe("projectVerificationActions — ABI 3 guidance", () => {
|
|
|
190
191
|
});
|
|
191
192
|
});
|
|
192
193
|
// ---------------------------------------------------------------------------
|
|
194
|
+
// projectAssessmentFields — ABI 3 expression projection
|
|
195
|
+
// ---------------------------------------------------------------------------
|
|
196
|
+
describe("projectAssessmentFields — ABI 3 expression", () => {
|
|
197
|
+
it("projects confidenceRationale and electionSummary from assessment", () => {
|
|
198
|
+
const result = scanResultWithAssessment(assessmentExpressAbi3);
|
|
199
|
+
const bundle = buildScanPresentationBundle({
|
|
200
|
+
result,
|
|
201
|
+
pipelineStatus: "done",
|
|
202
|
+
});
|
|
203
|
+
const fields = projectAssessmentFields(bundle);
|
|
204
|
+
expect(fields.confidenceRationale).toBe("Confidence is high: propagation from express to application entry points was directly observed.");
|
|
205
|
+
expect(fields.electionSummary).toBe(expressElectionSummary);
|
|
206
|
+
expect(fields.reasoning).toEqual(expressReasoning);
|
|
207
|
+
});
|
|
208
|
+
it("omits empty confidenceRationale and electionSummary after trim", () => {
|
|
209
|
+
const assessment = {
|
|
210
|
+
...assessmentExpressAbi3,
|
|
211
|
+
confidenceRationale: " ",
|
|
212
|
+
reviewFocalPoint: {
|
|
213
|
+
...assessmentExpressAbi3.reviewFocalPoint,
|
|
214
|
+
electionSummary: "",
|
|
215
|
+
},
|
|
216
|
+
};
|
|
217
|
+
const result = scanResultWithAssessment(assessment);
|
|
218
|
+
const bundle = buildScanPresentationBundle({
|
|
219
|
+
result,
|
|
220
|
+
pipelineStatus: "done",
|
|
221
|
+
});
|
|
222
|
+
const fields = projectAssessmentFields(bundle);
|
|
223
|
+
expect(fields.confidenceRationale).toBeUndefined();
|
|
224
|
+
expect(fields.electionSummary).toBeUndefined();
|
|
225
|
+
});
|
|
226
|
+
it("projects reasoning when assessment has concerns", () => {
|
|
227
|
+
const result = scanResultWithAssessment(assessmentExpressAbi3);
|
|
228
|
+
const bundle = buildScanPresentationBundle({
|
|
229
|
+
result,
|
|
230
|
+
pipelineStatus: "done",
|
|
231
|
+
});
|
|
232
|
+
const fields = projectAssessmentFields(bundle);
|
|
233
|
+
expect(assessmentExpressAbi3.concerns.length).toBeGreaterThan(0);
|
|
234
|
+
expect(fields.reasoning.length).toBeGreaterThan(0);
|
|
235
|
+
expect(fields.reasoning).toEqual(expressReasoning);
|
|
236
|
+
});
|
|
237
|
+
});
|
|
238
|
+
// ---------------------------------------------------------------------------
|
|
193
239
|
// PR comment — electionSummary and reasoning
|
|
194
240
|
// ---------------------------------------------------------------------------
|
|
195
241
|
describe("presentGitHubPrComment — ABI 3 expression", () => {
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* V1 public bundle transport — ScanPresentationBundle vs contracts extractor.
|
|
3
|
+
*
|
|
4
|
+
* Engine OutcomePresentationBundle uses the same `extractAuthoredCommunication()`
|
|
5
|
+
* from `@mergesignal/contracts`; engine-side accessor transport is covered in
|
|
6
|
+
* mergesignal-engine `packages/worker/src/outcome-presentation.test.ts`.
|
|
7
|
+
*/
|
|
8
|
+
export {};
|
|
9
|
+
//# sourceMappingURL=bundleAccessorParity.test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bundleAccessorParity.test.d.ts","sourceRoot":"","sources":["../../src/presentation/bundleAccessorParity.test.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG"}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* V1 public bundle transport — ScanPresentationBundle vs contracts extractor.
|
|
3
|
+
*
|
|
4
|
+
* Engine OutcomePresentationBundle uses the same `extractAuthoredCommunication()`
|
|
5
|
+
* from `@mergesignal/contracts`; engine-side accessor transport is covered in
|
|
6
|
+
* mergesignal-engine `packages/worker/src/outcome-presentation.test.ts`.
|
|
7
|
+
*/
|
|
8
|
+
import { extractAuthoredCommunication, parseAssessmentOrThrow, } from "@mergesignal/contracts";
|
|
9
|
+
import { describe, expect, it } from "vitest";
|
|
10
|
+
import { buildScanPresentationBundle } from "./orchestration/buildScanPresentationBundle.js";
|
|
11
|
+
function scanResultWith(assessment) {
|
|
12
|
+
return {
|
|
13
|
+
totalScore: 70,
|
|
14
|
+
layerScores: {
|
|
15
|
+
security: 70,
|
|
16
|
+
maintainability: 70,
|
|
17
|
+
ecosystem: 70,
|
|
18
|
+
upgradeImpact: 70,
|
|
19
|
+
},
|
|
20
|
+
findings: [],
|
|
21
|
+
generatedAt: "2026-01-01T00:00:00Z",
|
|
22
|
+
changedPackages: assessment.reviewFocalPoint.anchors,
|
|
23
|
+
methodologyVersion: "mergesignal-engine/test",
|
|
24
|
+
assessment,
|
|
25
|
+
decision: {
|
|
26
|
+
recommendation: "needs_review",
|
|
27
|
+
confidence: "medium",
|
|
28
|
+
reasoning: [],
|
|
29
|
+
},
|
|
30
|
+
insights: [],
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
function baseAssessment() {
|
|
34
|
+
return {
|
|
35
|
+
reviewFocalPoint: {
|
|
36
|
+
episodeShape: "single_anchor",
|
|
37
|
+
anchors: ["pkg-a"],
|
|
38
|
+
election: { grounding: [], exclusions: [] },
|
|
39
|
+
},
|
|
40
|
+
reachScope: { packages: ["pkg-a"], maxBucket: "moderate" },
|
|
41
|
+
verificationScope: { packages: ["pkg-a"], focus: [] },
|
|
42
|
+
posture: "needs_review",
|
|
43
|
+
confidence: "medium",
|
|
44
|
+
primaryConcern: null,
|
|
45
|
+
concerns: [],
|
|
46
|
+
factors: [],
|
|
47
|
+
changeClasses: [],
|
|
48
|
+
presentation: {
|
|
49
|
+
narrativeIntensity: "standard",
|
|
50
|
+
reachVisibility: "contextual",
|
|
51
|
+
verificationIntensity: "advisory",
|
|
52
|
+
insightEmissionFloor: "full",
|
|
53
|
+
reportMode: "high_signal_pr",
|
|
54
|
+
},
|
|
55
|
+
reasoning: [],
|
|
56
|
+
confidenceRationale: "Confidence is medium.",
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
function pickAccessors(bundle) {
|
|
60
|
+
return {
|
|
61
|
+
trustLine: bundle.trustLine,
|
|
62
|
+
whyThisPackageLine: bundle.whyThisPackageLine,
|
|
63
|
+
notAffectedLine: bundle.notAffectedLine,
|
|
64
|
+
resolutionLine: bundle.resolutionLine,
|
|
65
|
+
reasoningLines: [...bundle.reasoningLines],
|
|
66
|
+
guidanceLines: [...bundle.guidanceLines],
|
|
67
|
+
concernContextLines: [...bundle.concernContextLines],
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
function assertPublicBundleMatchesContractsExtractor(assessment, label) {
|
|
71
|
+
const normalized = parseAssessmentOrThrow(assessment);
|
|
72
|
+
const expected = extractAuthoredCommunication(normalized);
|
|
73
|
+
const publicBundle = buildScanPresentationBundle({
|
|
74
|
+
result: scanResultWith(assessment),
|
|
75
|
+
pipelineStatus: "done",
|
|
76
|
+
});
|
|
77
|
+
expect(publicBundle, `${label}: public bundle`).not.toBeNull();
|
|
78
|
+
expect(pickAccessors(publicBundle), label).toEqual(pickAccessors(expected));
|
|
79
|
+
}
|
|
80
|
+
describe("V1 bundle transport: public bundle matches contracts extractor", () => {
|
|
81
|
+
it("cleared: identical AuthoredCommunicationAccessors", () => {
|
|
82
|
+
assertPublicBundleMatchesContractsExtractor({
|
|
83
|
+
...baseAssessment(),
|
|
84
|
+
outcome: "cleared",
|
|
85
|
+
reasoning: ["Peer dependency constraints verified."],
|
|
86
|
+
notAffectedLine: "No repository code paths are affected by export compatibility — this dimension is outside the review scope.",
|
|
87
|
+
reviewFocalPoint: {
|
|
88
|
+
...baseAssessment().reviewFocalPoint,
|
|
89
|
+
electionSummary: "`pkg-a` was selected as the primary review anchor because it has the highest repository reach.",
|
|
90
|
+
},
|
|
91
|
+
}, "cleared");
|
|
92
|
+
});
|
|
93
|
+
it("bounded_verify: identical AuthoredCommunicationAccessors", () => {
|
|
94
|
+
assertPublicBundleMatchesContractsExtractor({
|
|
95
|
+
...baseAssessment(),
|
|
96
|
+
outcome: "bounded_verify",
|
|
97
|
+
reasoning: ["Automation stopped before all dimensions were verified."],
|
|
98
|
+
verificationScope: {
|
|
99
|
+
packages: ["pkg-a"],
|
|
100
|
+
focus: [],
|
|
101
|
+
guidance: ["Verify route handler at `src/server.ts:42`."],
|
|
102
|
+
},
|
|
103
|
+
resolutionLine: "A passing automated verification for this dimension would make this deterministic.",
|
|
104
|
+
concerns: [
|
|
105
|
+
{
|
|
106
|
+
kind: "confirmed_runtime_usage",
|
|
107
|
+
rank: 1,
|
|
108
|
+
packages: ["pkg-a"],
|
|
109
|
+
evidenceRefs: [],
|
|
110
|
+
context: "Runtime usage: `pkg-a` — used in 3 files.",
|
|
111
|
+
},
|
|
112
|
+
],
|
|
113
|
+
}, "bounded_verify");
|
|
114
|
+
});
|
|
115
|
+
it("abstain: identical AuthoredCommunicationAccessors", () => {
|
|
116
|
+
assertPublicBundleMatchesContractsExtractor({
|
|
117
|
+
...baseAssessment(),
|
|
118
|
+
outcome: "abstain",
|
|
119
|
+
reasoning: [
|
|
120
|
+
"Cannot verify `pkg-a`: package artifacts are not publicly accessible.",
|
|
121
|
+
],
|
|
122
|
+
resolutionLine: "Granting access to `pkg-a` artifacts or publishing them would allow deterministic verification.",
|
|
123
|
+
abstainReasons: [{ kind: "private_package", packageName: "pkg-a" }],
|
|
124
|
+
}, "abstain");
|
|
125
|
+
});
|
|
126
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cliParity.test.d.ts","sourceRoot":"","sources":["../../src/presentation/cliParity.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { buildScanPresentationBundle } from "./orchestration/buildScanPresentationBundle.js";
|
|
3
|
+
import { presentCliScanSummary } from "./presenters/presentCliScanSummary.js";
|
|
4
|
+
import { presentDashboardCard } from "./presenters/presentDashboardCard.js";
|
|
5
|
+
import { presentGitHubCheckRun } from "./presenters/presentGitHubCheckRun.js";
|
|
6
|
+
import { presentGitHubPrComment } from "./presenters/presentGitHubPrComment.js";
|
|
7
|
+
import { presentScanDetails } from "./presenters/presentScanDetails.js";
|
|
8
|
+
import { projectAssessmentFields } from "./projectAssessmentFields.js";
|
|
9
|
+
import { scanResultBullmq, scanResultEslint, scanResultFastifyRuntime, scanResultMixedTypescriptFastify, scanResultPrettier, scanResultTypescriptPatch, scanResultVitest, } from "./fixtures/presentationPersonaFixtures.js";
|
|
10
|
+
const SCAN_ID = "22222222-2222-4222-8222-222222222222";
|
|
11
|
+
const ORIGIN = "https://app.example.com";
|
|
12
|
+
const validationPersonas = [
|
|
13
|
+
{ name: "mixed-ts-fastify", result: scanResultMixedTypescriptFastify },
|
|
14
|
+
{ name: "fastify-runtime", result: scanResultFastifyRuntime },
|
|
15
|
+
{ name: "typescript-patch", result: scanResultTypescriptPatch },
|
|
16
|
+
{ name: "prettier", result: scanResultPrettier },
|
|
17
|
+
{ name: "bullmq", result: scanResultBullmq },
|
|
18
|
+
{ name: "eslint", result: scanResultEslint },
|
|
19
|
+
{ name: "vitest", result: scanResultVitest },
|
|
20
|
+
];
|
|
21
|
+
describe("cliParity guardrail", () => {
|
|
22
|
+
for (const persona of validationPersonas) {
|
|
23
|
+
it(`${persona.name}: CLI shares assessment fields with other surfaces`, () => {
|
|
24
|
+
const bundle = buildScanPresentationBundle({
|
|
25
|
+
result: persona.result,
|
|
26
|
+
pipelineStatus: "done",
|
|
27
|
+
});
|
|
28
|
+
const fields = projectAssessmentFields(bundle);
|
|
29
|
+
const cli = presentCliScanSummary(bundle, { repoLabel: "acme/api" });
|
|
30
|
+
const card = presentDashboardCard(bundle);
|
|
31
|
+
const details = presentScanDetails(bundle, { scanId: SCAN_ID });
|
|
32
|
+
const check = presentGitHubCheckRun(bundle, {
|
|
33
|
+
scanId: SCAN_ID,
|
|
34
|
+
webAppOrigin: ORIGIN,
|
|
35
|
+
});
|
|
36
|
+
const comment = presentGitHubPrComment(bundle);
|
|
37
|
+
expect(cli.posture).toBe(fields.posture);
|
|
38
|
+
expect(cli.reasoning).toEqual(fields.reasoning);
|
|
39
|
+
expect(cli.verificationChannel).toBe(fields.verificationChannel);
|
|
40
|
+
expect(cli.verificationFocus).toEqual(fields.verificationFocus);
|
|
41
|
+
expect(cli.confidenceRationale).toBe(fields.confidenceRationale);
|
|
42
|
+
expect(cli.electionSummary).toBe(fields.electionSummary);
|
|
43
|
+
expect(cli.reasoning).toEqual(card.reasoning);
|
|
44
|
+
expect(cli.reasoning).toEqual(details.reasoning);
|
|
45
|
+
expect(cli.reasoning).toEqual(check.reasoning);
|
|
46
|
+
expect(cli.reasoning).toEqual(comment.reasoning);
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
});
|
|
@@ -5,10 +5,6 @@ export declare function composeSubheadline(bundle: ScanPresentationBundle): stri
|
|
|
5
5
|
export declare function composeKeyPoints(bundle: ScanPresentationBundle, max: number): string[];
|
|
6
6
|
export declare function composeVerificationActions(bundle: ScanPresentationBundle, max: number): string[];
|
|
7
7
|
export declare function composeAffectedAreaLabels(bundle: ScanPresentationBundle, max: number): string[];
|
|
8
|
-
export declare function composeEvidenceRows(bundle: ScanPresentationBundle, max: number): Array<{
|
|
9
|
-
label: string;
|
|
10
|
-
value: string;
|
|
11
|
-
}>;
|
|
12
8
|
export declare function composeSupportingContext(bundle: ScanPresentationBundle): string[] | undefined;
|
|
13
9
|
export declare function evidenceContextFromProfile(bundle: ScanPresentationBundle): {
|
|
14
10
|
priority: "pr_intelligence" | "limited";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"narrativeCompose.d.ts","sourceRoot":"","sources":["../../../src/presentation/compose/narrativeCompose.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"narrativeCompose.d.ts","sourceRoot":"","sources":["../../../src/presentation/compose/narrativeCompose.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,4CAA4C,CAAC;AAMzF,OAAO,EACL,sBAAsB,EACtB,uBAAuB,GACxB,MAAM,wBAAwB,CAAC;AAShC,wBAAgB,eAAe,CAAC,MAAM,EAAE,sBAAsB,GAAG,MAAM,CAEtE;AAED,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,sBAAsB,GAC7B,MAAM,GAAG,SAAS,CAIpB;AAED,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,sBAAsB,EAC9B,GAAG,EAAE,MAAM,GACV,MAAM,EAAE,CAEV;AAED,wBAAgB,0BAA0B,CACxC,MAAM,EAAE,sBAAsB,EAC9B,GAAG,EAAE,MAAM,GACV,MAAM,EAAE,CAEV;AAED,wBAAgB,yBAAyB,CACvC,MAAM,EAAE,sBAAsB,EAC9B,GAAG,EAAE,MAAM,GACV,MAAM,EAAE,CAQV;AAED,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,sBAAsB,GAC7B,MAAM,EAAE,GAAG,SAAS,CAwBtB;AAED,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,sBAAsB,GAAG;IAC1E,QAAQ,EAAE,iBAAiB,GAAG,SAAS,CAAC;IACxC,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B,CAKA"}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { formatCardAreaLabels } from "../../formatCardAreaLabels.js";
|
|
2
|
-
import { formatChangedPackagesShort, labelBlastRadiusLevel, labelReachabilityKind, labelRuntimeSurface, } from "../../narrativePresentation.js";
|
|
3
2
|
import { scanSurfaceCopy } from "../../scanSurfaceCopy.js";
|
|
4
3
|
import { buildNarrativeChannels, projectCompactKeyPoints, } from "./narrativeChannels.js";
|
|
5
4
|
export { buildNarrativeChannels, projectCompactKeyPoints, } from "./narrativeChannels.js";
|
|
@@ -36,25 +35,6 @@ export function composeAffectedAreaLabels(bundle, max) {
|
|
|
36
35
|
}
|
|
37
36
|
return labels;
|
|
38
37
|
}
|
|
39
|
-
export function composeEvidenceRows(bundle, max) {
|
|
40
|
-
const { facts, profile } = bundle;
|
|
41
|
-
const rows = [];
|
|
42
|
-
if (!profile.interpretation.suppressRuntimeNarrative) {
|
|
43
|
-
const runtime = labelRuntimeSurface(facts);
|
|
44
|
-
if (runtime)
|
|
45
|
-
rows.push({ label: "Runtime", value: runtime });
|
|
46
|
-
const reach = labelReachabilityKind(facts);
|
|
47
|
-
if (reach)
|
|
48
|
-
rows.push({ label: "Reachability", value: reach });
|
|
49
|
-
}
|
|
50
|
-
const blast = labelBlastRadiusLevel(facts);
|
|
51
|
-
if (blast)
|
|
52
|
-
rows.push({ label: "Blast radius", value: blast });
|
|
53
|
-
const changed = formatChangedPackagesShort(facts, 3);
|
|
54
|
-
if (changed)
|
|
55
|
-
rows.push({ label: "Changed", value: changed });
|
|
56
|
-
return rows.slice(0, max);
|
|
57
|
-
}
|
|
58
38
|
export function composeSupportingContext(bundle) {
|
|
59
39
|
const { facts, profile, result } = bundle;
|
|
60
40
|
if (profile.density === "minimal")
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"decisionSurface.test.d.ts","sourceRoot":"","sources":["../../src/presentation/decisionSurface.test.ts"],"names":[],"mappings":""}
|