@mergesignal/shared 0.11.0 → 0.12.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/assessmentProjection.d.ts.map +1 -1
- package/dist/assessmentProjection.js +11 -4
- package/dist/fixtures/assessmentScopeFixtures.d.ts +5 -2
- package/dist/fixtures/assessmentScopeFixtures.d.ts.map +1 -1
- package/dist/fixtures/assessmentScopeFixtures.js +3 -1
- package/dist/presentation/abi3Expression.test.d.ts +13 -0
- package/dist/presentation/abi3Expression.test.d.ts.map +1 -0
- package/dist/presentation/abi3Expression.test.js +346 -0
- package/dist/presentation/presenters/presentGitHubCheckRun.d.ts.map +1 -1
- package/dist/presentation/presenters/presentGitHubCheckRun.js +10 -4
- package/dist/presentation/presenters/presentGitHubPrComment.d.ts.map +1 -1
- package/dist/presentation/presenters/presentGitHubPrComment.js +3 -0
- package/dist/scanResultSchema.d.ts +7 -0
- package/dist/scanResultSchema.d.ts.map +1 -1
- package/dist/scanResultSchema.test.js +2 -0
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"assessmentProjection.d.ts","sourceRoot":"","sources":["../src/assessmentProjection.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,EAEL,KAAK,gBAAgB,EACtB,MAAM,6BAA6B,CAAC;AACrC,OAAO,KAAK,EACV,UAAU,EACV,4BAA4B,EAC5B,eAAe,EACf,qBAAqB,EACtB,MAAM,wBAAwB,CAAC;AAOhC,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,6BAA6B,CAAC;AAEtE,MAAM,MAAM,mBAAmB,GAAG,SAAS,GAAG,UAAU,GAAG,MAAM,CAAC;AAmDlE,wBAAgB,0BAA0B,CACxC,SAAS,EAAE,qBAAqB,GAC/B,mBAAmB,CAIrB;AAED,wBAAgB,+BAA+B,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,EAAE,CAQ5E;AAED,wBAAgB,gCAAgC,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,EAAE,CAS7E;AAED,wBAAgB,uCAAuC,CACrD,YAAY,EAAE,4BAA4B,EAC1C,MAAM,EAAE,UAAU,GACjB;IAAE,OAAO,EAAE,mBAAmB,CAAC;IAAC,KAAK,EAAE,MAAM,EAAE,CAAA;CAAE,CAWnD;AAED,8FAA8F;AAC9F,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,EAAE,CAErE;AAED,wBAAgB,oBAAoB,CAClC,UAAU,EAAE,eAAe,GAC1B,MAAM,GAAG,SAAS,CAWpB;AAED,wBAAgB,wBAAwB,CACtC,UAAU,EAAE,UAAU,EACtB,MAAM,EAAE,kBAAkB,GACzB,MAAM,CAiDR;AAED,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,EAAE,
|
|
1
|
+
{"version":3,"file":"assessmentProjection.d.ts","sourceRoot":"","sources":["../src/assessmentProjection.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,EAEL,KAAK,gBAAgB,EACtB,MAAM,6BAA6B,CAAC;AACrC,OAAO,KAAK,EACV,UAAU,EACV,4BAA4B,EAC5B,eAAe,EACf,qBAAqB,EACtB,MAAM,wBAAwB,CAAC;AAOhC,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,6BAA6B,CAAC;AAEtE,MAAM,MAAM,mBAAmB,GAAG,SAAS,GAAG,UAAU,GAAG,MAAM,CAAC;AAmDlE,wBAAgB,0BAA0B,CACxC,SAAS,EAAE,qBAAqB,GAC/B,mBAAmB,CAIrB;AAED,wBAAgB,+BAA+B,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,EAAE,CAQ5E;AAED,wBAAgB,gCAAgC,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,EAAE,CAS7E;AAED,wBAAgB,uCAAuC,CACrD,YAAY,EAAE,4BAA4B,EAC1C,MAAM,EAAE,UAAU,GACjB;IAAE,OAAO,EAAE,mBAAmB,CAAC;IAAC,KAAK,EAAE,MAAM,EAAE,CAAA;CAAE,CAWnD;AAED,8FAA8F;AAC9F,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,EAAE,CAErE;AAED,wBAAgB,oBAAoB,CAClC,UAAU,EAAE,eAAe,GAC1B,MAAM,GAAG,SAAS,CAWpB;AAED,wBAAgB,wBAAwB,CACtC,UAAU,EAAE,UAAU,EACtB,MAAM,EAAE,kBAAkB,GACzB,MAAM,CAiDR;AAED,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,EAAE,CAMlE;AAED,wBAAgB,mBAAmB,CACjC,UAAU,EAAE,UAAU,EACtB,MAAM,EAAE,UAAU,GACjB,MAAM,EAAE,CAaV;AAED,wBAAgB,0BAA0B,CACxC,UAAU,EAAE,UAAU,EACtB,YAAY,EAAE,4BAA4B,EAC1C,MAAM,EAAE,UAAU,EAClB,GAAG,EAAE,MAAM,GACV,MAAM,EAAE,CAWV;AAED,wBAAgB,qBAAqB,CAAC,EAAE,EAAE,gBAAgB,GAAG,IAAI,GAAG,MAAM,EAAE,CAI3E"}
|
|
@@ -126,10 +126,12 @@ export function formatAssessmentHeadline(assessment, status) {
|
|
|
126
126
|
return applyPostureVocabularyGuardHeadline(copy.defaultUpgradeHeadline.replace("{package}", primaryPkg), status, primaryPkg);
|
|
127
127
|
}
|
|
128
128
|
export function projectReasoningLines(result) {
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
129
|
+
// ABI 3: assessment.reasoning is the authoritative source for repository-specific prose
|
|
130
|
+
const fromAssessment = result.assessment?.reasoning?.filter(Boolean) ?? [];
|
|
131
|
+
if (fromAssessment.length > 0)
|
|
132
|
+
return fromAssessment;
|
|
133
|
+
// Fallback for pre-ABI-3 scan results still in the database
|
|
134
|
+
return result.decision?.reasoning?.filter(Boolean) ?? [];
|
|
133
135
|
}
|
|
134
136
|
export function projectInsightLines(assessment, result) {
|
|
135
137
|
const reasoning = projectReasoningLines(result);
|
|
@@ -149,6 +151,11 @@ export function projectInsightLines(assessment, result) {
|
|
|
149
151
|
export function projectVerificationActions(assessment, presentation, result, max) {
|
|
150
152
|
if (presentation.verificationIntensity === "none")
|
|
151
153
|
return [];
|
|
154
|
+
// ABI 3: use actionable prose guidance when present
|
|
155
|
+
const guidance = assessment.verificationScope?.guidance;
|
|
156
|
+
if (guidance && guidance.length > 0)
|
|
157
|
+
return guidance.slice(0, max);
|
|
158
|
+
// Fallback: focus tokens from legacy scope or repoIntelligence
|
|
152
159
|
const { focus } = collectVerificationFocusForPresentation(presentation, result);
|
|
153
160
|
return focus.slice(0, max);
|
|
154
161
|
}
|
|
@@ -10,8 +10,11 @@ export declare function emptyArtifactGrounded(): ArtifactGroundedVerificationSco
|
|
|
10
10
|
export declare function artifactGroundedScopeFor(packages: string[], focus?: string[], artifactPaths?: string[]): ArtifactGroundedVerificationScope;
|
|
11
11
|
export declare function emptyVerificationScope(): VerificationScope;
|
|
12
12
|
export declare function verificationScopeFor(packages: string[], focus?: string[], artifactGrounded?: ArtifactGroundedVerificationScope): VerificationScope;
|
|
13
|
-
/** Attach focal/scope fields required by assessmentSchema ABI
|
|
14
|
-
export declare function withAssessmentScope(assessment: Omit<Assessment, "reviewFocalPoint" | "reachScope" | "verificationScope"
|
|
13
|
+
/** Attach focal/scope fields required by assessmentSchema ABI 3. */
|
|
14
|
+
export declare function withAssessmentScope(assessment: Omit<Assessment, "reviewFocalPoint" | "reachScope" | "verificationScope" | "reasoning" | "confidenceRationale"> & {
|
|
15
|
+
reasoning?: string[];
|
|
16
|
+
confidenceRationale?: string;
|
|
17
|
+
}, scope: {
|
|
15
18
|
reviewFocalPoint: ReviewFocalPoint;
|
|
16
19
|
reachScope?: ReachScope;
|
|
17
20
|
verificationScope?: VerificationScope;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"assessmentScopeFixtures.d.ts","sourceRoot":"","sources":["../../src/fixtures/assessmentScopeFixtures.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,iCAAiC,EACjC,UAAU,EACV,sBAAsB,EACtB,UAAU,EACV,kBAAkB,EAClB,gBAAgB,EAChB,iBAAiB,EAClB,MAAM,wBAAwB,CAAC;AAEhC,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,MAAM,EAAE,EACjB,IAAI,CAAC,EAAE;IACL,YAAY,CAAC,EAAE,kBAAkB,CAAC;IAClC,kBAAkB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC9B,SAAS,CAAC,EAAE,sBAAsB,CAAC;CACpC,GACA,gBAAgB,CAoBlB;AAED,wBAAgB,eAAe,IAAI,UAAU,CAE5C;AAED,wBAAgB,aAAa,CAC3B,QAAQ,EAAE,MAAM,EAAE,EAClB,SAAS,GAAE,UAAU,CAAC,WAAW,CAAc,GAC9C,UAAU,CAEZ;AAED,wBAAgB,qBAAqB,IAAI,iCAAiC,CAEzE;AAED,wBAAgB,wBAAwB,CACtC,QAAQ,EAAE,MAAM,EAAE,EAClB,KAAK,GAAE,MAAM,EAAO,EACpB,aAAa,GAAE,MAAM,EAAO,GAC3B,iCAAiC,CAEnC;AAED,wBAAgB,sBAAsB,IAAI,iBAAiB,CAM1D;AAED,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,MAAM,EAAE,EAClB,KAAK,GAAE,MAAM,EAAO,EACpB,gBAAgB,GAAE,iCAA2D,GAC5E,iBAAiB,CAEnB;AAED,oEAAoE;AACpE,wBAAgB,mBAAmB,CACjC,UAAU,EAAE,IAAI,CACd,UAAU,
|
|
1
|
+
{"version":3,"file":"assessmentScopeFixtures.d.ts","sourceRoot":"","sources":["../../src/fixtures/assessmentScopeFixtures.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,iCAAiC,EACjC,UAAU,EACV,sBAAsB,EACtB,UAAU,EACV,kBAAkB,EAClB,gBAAgB,EAChB,iBAAiB,EAClB,MAAM,wBAAwB,CAAC;AAEhC,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,MAAM,EAAE,EACjB,IAAI,CAAC,EAAE;IACL,YAAY,CAAC,EAAE,kBAAkB,CAAC;IAClC,kBAAkB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC9B,SAAS,CAAC,EAAE,sBAAsB,CAAC;CACpC,GACA,gBAAgB,CAoBlB;AAED,wBAAgB,eAAe,IAAI,UAAU,CAE5C;AAED,wBAAgB,aAAa,CAC3B,QAAQ,EAAE,MAAM,EAAE,EAClB,SAAS,GAAE,UAAU,CAAC,WAAW,CAAc,GAC9C,UAAU,CAEZ;AAED,wBAAgB,qBAAqB,IAAI,iCAAiC,CAEzE;AAED,wBAAgB,wBAAwB,CACtC,QAAQ,EAAE,MAAM,EAAE,EAClB,KAAK,GAAE,MAAM,EAAO,EACpB,aAAa,GAAE,MAAM,EAAO,GAC3B,iCAAiC,CAEnC;AAED,wBAAgB,sBAAsB,IAAI,iBAAiB,CAM1D;AAED,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,MAAM,EAAE,EAClB,KAAK,GAAE,MAAM,EAAO,EACpB,gBAAgB,GAAE,iCAA2D,GAC5E,iBAAiB,CAEnB;AAED,oEAAoE;AACpE,wBAAgB,mBAAmB,CACjC,UAAU,EAAE,IAAI,CACd,UAAU,EACR,kBAAkB,GAClB,YAAY,GACZ,mBAAmB,GACnB,WAAW,GACX,qBAAqB,CACxB,GAAG;IAAE,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IAAC,mBAAmB,CAAC,EAAE,MAAM,CAAA;CAAE,EAC1D,KAAK,EAAE;IACL,gBAAgB,EAAE,gBAAgB,CAAC;IACnC,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB,iBAAiB,CAAC,EAAE,iBAAiB,CAAC;CACvC,GACA,UAAU,CASZ"}
|
|
@@ -41,9 +41,11 @@ export function emptyVerificationScope() {
|
|
|
41
41
|
export function verificationScopeFor(packages, focus = [], artifactGrounded = emptyArtifactGrounded()) {
|
|
42
42
|
return { packages, focus, artifactGrounded };
|
|
43
43
|
}
|
|
44
|
-
/** Attach focal/scope fields required by assessmentSchema ABI
|
|
44
|
+
/** Attach focal/scope fields required by assessmentSchema ABI 3. */
|
|
45
45
|
export function withAssessmentScope(assessment, scope) {
|
|
46
46
|
return {
|
|
47
|
+
reasoning: [],
|
|
48
|
+
confidenceRationale: "",
|
|
47
49
|
...assessment,
|
|
48
50
|
reviewFocalPoint: scope.reviewFocalPoint,
|
|
49
51
|
reachScope: scope.reachScope ?? emptyReachScope(),
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wave 2.D — ABI 3 expression validation.
|
|
3
|
+
*
|
|
4
|
+
* Validates that:
|
|
5
|
+
* 1. projectReasoningLines reads from assessment.reasoning (ABI 3) when present
|
|
6
|
+
* 2. projectVerificationActions returns assessment.verificationScope.guidance when present
|
|
7
|
+
* 3. PR comment includes reviewFocalPoint.electionSummary when present
|
|
8
|
+
* 4. Check run "Why" section uses assessment.reasoning lines directly
|
|
9
|
+
* 5. No prohibited vocabulary appears in rendered surfaces
|
|
10
|
+
* 6. assessment.reasoning takes priority over decision.reasoning
|
|
11
|
+
*/
|
|
12
|
+
export {};
|
|
13
|
+
//# sourceMappingURL=abi3Expression.test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"abi3Expression.test.d.ts","sourceRoot":"","sources":["../../src/presentation/abi3Expression.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG"}
|
|
@@ -0,0 +1,346 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wave 2.D — ABI 3 expression validation.
|
|
3
|
+
*
|
|
4
|
+
* Validates that:
|
|
5
|
+
* 1. projectReasoningLines reads from assessment.reasoning (ABI 3) when present
|
|
6
|
+
* 2. projectVerificationActions returns assessment.verificationScope.guidance when present
|
|
7
|
+
* 3. PR comment includes reviewFocalPoint.electionSummary when present
|
|
8
|
+
* 4. Check run "Why" section uses assessment.reasoning lines directly
|
|
9
|
+
* 5. No prohibited vocabulary appears in rendered surfaces
|
|
10
|
+
* 6. assessment.reasoning takes priority over decision.reasoning
|
|
11
|
+
*/
|
|
12
|
+
import { describe, expect, it } from "vitest";
|
|
13
|
+
import { minimalReviewFocalPoint, reachScopeFor, verificationScopeFor, withAssessmentScope, } from "../fixtures/assessmentScopeFixtures.js";
|
|
14
|
+
import { projectReasoningLines, projectVerificationActions, } from "../assessmentProjection.js";
|
|
15
|
+
import { toPublicPresentation } from "../assessmentPresentationUtils.js";
|
|
16
|
+
import { buildScanPresentationBundle } from "./orchestration/buildScanPresentationBundle.js";
|
|
17
|
+
import { presentGitHubPrComment } from "./presenters/presentGitHubPrComment.js";
|
|
18
|
+
import { presentGitHubCheckRun } from "./presenters/presentGitHubCheckRun.js";
|
|
19
|
+
import { buildGitHubCheckRunOutput } from "./buildGitHubCheckRunOutput.js";
|
|
20
|
+
import { presentGitHubPrCommentMarkdownFromResult } from "../presentGitHubPrComment.js";
|
|
21
|
+
// ---------------------------------------------------------------------------
|
|
22
|
+
// ABI 3 — Canonical express/confirmed_runtime_usage fixture
|
|
23
|
+
// ---------------------------------------------------------------------------
|
|
24
|
+
const expressReasoning = [
|
|
25
|
+
"express is used in HTTP request handling in this repository via middleware chains.",
|
|
26
|
+
"Import paths to application entry points were directly observed.",
|
|
27
|
+
"Verification is required: review HTTP route definitions and middleware implementation.",
|
|
28
|
+
];
|
|
29
|
+
const expressGuidance = [
|
|
30
|
+
"Review HTTP route definitions and middleware implementation in src/app.ts and src/server.ts.",
|
|
31
|
+
"Review handler implementations that use express routing.",
|
|
32
|
+
];
|
|
33
|
+
const expressElectionSummary = "express was selected as the primary review anchor because it has the highest repository reach among changed packages and confirmed runtime usage in HTTP request handling.";
|
|
34
|
+
const assessmentExpressAbi3 = withAssessmentScope({
|
|
35
|
+
posture: "needs_review",
|
|
36
|
+
confidence: "high",
|
|
37
|
+
primaryConcern: "confirmed_runtime_usage",
|
|
38
|
+
concerns: [
|
|
39
|
+
{
|
|
40
|
+
kind: "confirmed_runtime_usage",
|
|
41
|
+
rank: 1,
|
|
42
|
+
packages: ["express"],
|
|
43
|
+
evidenceRefs: ["fixture:express"],
|
|
44
|
+
context: "express participates in HTTP request handling across 12 files.",
|
|
45
|
+
},
|
|
46
|
+
],
|
|
47
|
+
factors: ["confirmed_runtime_usage", "http_framework_infrastructure"],
|
|
48
|
+
changeClasses: ["runtime_upgrade"],
|
|
49
|
+
presentation: {
|
|
50
|
+
narrativeIntensity: "elevated",
|
|
51
|
+
reachVisibility: "prominent",
|
|
52
|
+
verificationIntensity: "required",
|
|
53
|
+
insightEmissionFloor: "full",
|
|
54
|
+
reportMode: "high_signal_pr",
|
|
55
|
+
},
|
|
56
|
+
reasoning: expressReasoning,
|
|
57
|
+
confidenceRationale: "Confidence is high: propagation from express to application entry points was directly observed.",
|
|
58
|
+
}, {
|
|
59
|
+
reviewFocalPoint: {
|
|
60
|
+
...minimalReviewFocalPoint(["express"]),
|
|
61
|
+
electionSummary: expressElectionSummary,
|
|
62
|
+
},
|
|
63
|
+
reachScope: reachScopeFor(["express"], "high"),
|
|
64
|
+
verificationScope: verificationScopeFor(["express"], ["routes", "middleware"], undefined),
|
|
65
|
+
});
|
|
66
|
+
const assessmentExpressAbi3WithGuidance = {
|
|
67
|
+
...assessmentExpressAbi3,
|
|
68
|
+
verificationScope: {
|
|
69
|
+
...assessmentExpressAbi3.verificationScope,
|
|
70
|
+
guidance: expressGuidance,
|
|
71
|
+
},
|
|
72
|
+
};
|
|
73
|
+
function scanResultWithAssessment(assessment, overrides = {}) {
|
|
74
|
+
return {
|
|
75
|
+
totalScore: 63,
|
|
76
|
+
layerScores: {
|
|
77
|
+
security: 10,
|
|
78
|
+
maintainability: 20,
|
|
79
|
+
ecosystem: 30,
|
|
80
|
+
upgradeImpact: 15,
|
|
81
|
+
},
|
|
82
|
+
findings: [],
|
|
83
|
+
generatedAt: "2026-01-01T00:00:00.000Z",
|
|
84
|
+
changedPackages: ["express"],
|
|
85
|
+
assessment,
|
|
86
|
+
decision: {
|
|
87
|
+
recommendation: "needs_review",
|
|
88
|
+
confidence: "high",
|
|
89
|
+
reasoning: ["Old generic decision reasoning — should not appear."],
|
|
90
|
+
},
|
|
91
|
+
...overrides,
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
// ---------------------------------------------------------------------------
|
|
95
|
+
// projectReasoningLines — ABI 3 priority
|
|
96
|
+
// ---------------------------------------------------------------------------
|
|
97
|
+
describe("projectReasoningLines — ABI 3", () => {
|
|
98
|
+
it("returns assessment.reasoning when present (ABI 3 takes priority)", () => {
|
|
99
|
+
const result = scanResultWithAssessment(assessmentExpressAbi3);
|
|
100
|
+
const lines = projectReasoningLines(result);
|
|
101
|
+
expect(lines).toEqual(expressReasoning);
|
|
102
|
+
});
|
|
103
|
+
it("assessment.reasoning takes priority over decision.reasoning", () => {
|
|
104
|
+
const result = scanResultWithAssessment(assessmentExpressAbi3);
|
|
105
|
+
const lines = projectReasoningLines(result);
|
|
106
|
+
expect(lines).not.toContain("Old generic decision reasoning — should not appear.");
|
|
107
|
+
});
|
|
108
|
+
it("falls back to decision.reasoning when assessment.reasoning is empty", () => {
|
|
109
|
+
const assessmentWithoutReasoning = {
|
|
110
|
+
...assessmentExpressAbi3,
|
|
111
|
+
reasoning: [],
|
|
112
|
+
};
|
|
113
|
+
const result = scanResultWithAssessment(assessmentWithoutReasoning);
|
|
114
|
+
const lines = projectReasoningLines(result);
|
|
115
|
+
expect(lines).toEqual([
|
|
116
|
+
"Old generic decision reasoning — should not appear.",
|
|
117
|
+
]);
|
|
118
|
+
});
|
|
119
|
+
it("returns empty array when both reasoning sources are absent", () => {
|
|
120
|
+
const assessmentEmpty = {
|
|
121
|
+
...assessmentExpressAbi3,
|
|
122
|
+
reasoning: [],
|
|
123
|
+
};
|
|
124
|
+
const result = scanResultWithAssessment(assessmentEmpty, {
|
|
125
|
+
decision: {
|
|
126
|
+
recommendation: "needs_review",
|
|
127
|
+
confidence: "high",
|
|
128
|
+
reasoning: [],
|
|
129
|
+
},
|
|
130
|
+
});
|
|
131
|
+
const lines = projectReasoningLines(result);
|
|
132
|
+
expect(lines).toEqual([]);
|
|
133
|
+
});
|
|
134
|
+
it("reasoning lines contain no prohibited vocabulary", () => {
|
|
135
|
+
const result = scanResultWithAssessment(assessmentExpressAbi3);
|
|
136
|
+
const lines = projectReasoningLines(result);
|
|
137
|
+
const joined = lines.join(" ");
|
|
138
|
+
const prohibited = [
|
|
139
|
+
"qualityClass",
|
|
140
|
+
"qualityBasis",
|
|
141
|
+
"proofFingerprint",
|
|
142
|
+
"observationId",
|
|
143
|
+
"propagationQualityRank",
|
|
144
|
+
"AssessmentEvidenceBundle",
|
|
145
|
+
"DenseEvidenceHighlight",
|
|
146
|
+
"will affect",
|
|
147
|
+
"will break",
|
|
148
|
+
"breaks compatibility",
|
|
149
|
+
"remain compatible",
|
|
150
|
+
"critical path",
|
|
151
|
+
];
|
|
152
|
+
for (const term of prohibited) {
|
|
153
|
+
expect(joined).not.toContain(term);
|
|
154
|
+
}
|
|
155
|
+
});
|
|
156
|
+
});
|
|
157
|
+
// ---------------------------------------------------------------------------
|
|
158
|
+
// projectVerificationActions — guidance priority
|
|
159
|
+
// ---------------------------------------------------------------------------
|
|
160
|
+
describe("projectVerificationActions — ABI 3 guidance", () => {
|
|
161
|
+
const presentation = toPublicPresentation(assessmentExpressAbi3WithGuidance.presentation);
|
|
162
|
+
it("returns guidance prose when verificationScope.guidance is present", () => {
|
|
163
|
+
const result = scanResultWithAssessment(assessmentExpressAbi3WithGuidance);
|
|
164
|
+
const actions = projectVerificationActions(assessmentExpressAbi3WithGuidance, presentation, result, 6);
|
|
165
|
+
expect(actions).toEqual(expressGuidance);
|
|
166
|
+
});
|
|
167
|
+
it("guidance respects max limit", () => {
|
|
168
|
+
const result = scanResultWithAssessment(assessmentExpressAbi3WithGuidance);
|
|
169
|
+
const actions = projectVerificationActions(assessmentExpressAbi3WithGuidance, presentation, result, 1);
|
|
170
|
+
expect(actions).toHaveLength(1);
|
|
171
|
+
expect(actions[0]).toBe(expressGuidance[0]);
|
|
172
|
+
});
|
|
173
|
+
it("falls back to focus tokens when guidance is absent", () => {
|
|
174
|
+
const result = scanResultWithAssessment(assessmentExpressAbi3);
|
|
175
|
+
const actions = projectVerificationActions(assessmentExpressAbi3, presentation, result, 6);
|
|
176
|
+
// No guidance — falls back to runtime focus tokens
|
|
177
|
+
expect(actions).toEqual(expect.arrayContaining(["routes", "middleware"]));
|
|
178
|
+
});
|
|
179
|
+
it("returns empty when verificationIntensity is none", () => {
|
|
180
|
+
const noneAssessment = {
|
|
181
|
+
...assessmentExpressAbi3WithGuidance,
|
|
182
|
+
presentation: {
|
|
183
|
+
...assessmentExpressAbi3WithGuidance.presentation,
|
|
184
|
+
verificationIntensity: "none",
|
|
185
|
+
},
|
|
186
|
+
};
|
|
187
|
+
const result = scanResultWithAssessment(noneAssessment);
|
|
188
|
+
const actions = projectVerificationActions(noneAssessment, toPublicPresentation(noneAssessment.presentation), result, 6);
|
|
189
|
+
expect(actions).toEqual([]);
|
|
190
|
+
});
|
|
191
|
+
});
|
|
192
|
+
// ---------------------------------------------------------------------------
|
|
193
|
+
// PR comment — electionSummary and reasoning
|
|
194
|
+
// ---------------------------------------------------------------------------
|
|
195
|
+
describe("presentGitHubPrComment — ABI 3 expression", () => {
|
|
196
|
+
function buildBundle(assessment) {
|
|
197
|
+
const result = scanResultWithAssessment(assessment, {
|
|
198
|
+
changedPackages: ["express"],
|
|
199
|
+
});
|
|
200
|
+
return buildScanPresentationBundle({ result, pipelineStatus: "done" });
|
|
201
|
+
}
|
|
202
|
+
it("introLines include electionSummary when present", () => {
|
|
203
|
+
const bundle = buildBundle(assessmentExpressAbi3);
|
|
204
|
+
const comment = presentGitHubPrComment(bundle);
|
|
205
|
+
expect(comment.introLines).toContain(expressElectionSummary);
|
|
206
|
+
});
|
|
207
|
+
it("introLines include assessment.reasoning sentences", () => {
|
|
208
|
+
const bundle = buildBundle(assessmentExpressAbi3);
|
|
209
|
+
const comment = presentGitHubPrComment(bundle);
|
|
210
|
+
const joined = comment.introLines.join(" ");
|
|
211
|
+
expect(joined).toContain("express is used in HTTP request handling");
|
|
212
|
+
expect(joined).toContain("Import paths to application entry points");
|
|
213
|
+
});
|
|
214
|
+
it("electionSummary is absent from introLines when not set", () => {
|
|
215
|
+
const assessmentNoElection = {
|
|
216
|
+
...assessmentExpressAbi3,
|
|
217
|
+
reviewFocalPoint: {
|
|
218
|
+
...assessmentExpressAbi3.reviewFocalPoint,
|
|
219
|
+
electionSummary: undefined,
|
|
220
|
+
},
|
|
221
|
+
};
|
|
222
|
+
const bundle = buildBundle(assessmentNoElection);
|
|
223
|
+
const comment = presentGitHubPrComment(bundle);
|
|
224
|
+
expect(comment.introLines).not.toContain(expressElectionSummary);
|
|
225
|
+
});
|
|
226
|
+
it("introLines contain no prohibited vocabulary", () => {
|
|
227
|
+
const bundle = buildBundle(assessmentExpressAbi3);
|
|
228
|
+
const comment = presentGitHubPrComment(bundle);
|
|
229
|
+
const joined = comment.introLines.join(" ");
|
|
230
|
+
const prohibited = [
|
|
231
|
+
"qualityClass",
|
|
232
|
+
"qualityBasis",
|
|
233
|
+
"proofFingerprint",
|
|
234
|
+
"observationId",
|
|
235
|
+
"propagationQualityRank",
|
|
236
|
+
];
|
|
237
|
+
for (const term of prohibited) {
|
|
238
|
+
expect(joined).not.toContain(term);
|
|
239
|
+
}
|
|
240
|
+
});
|
|
241
|
+
});
|
|
242
|
+
// ---------------------------------------------------------------------------
|
|
243
|
+
// Check run — Why section uses assessment.reasoning
|
|
244
|
+
// ---------------------------------------------------------------------------
|
|
245
|
+
describe("presentGitHubCheckRun — ABI 3 Why section", () => {
|
|
246
|
+
const SCAN_ID = "scan-abi3-test";
|
|
247
|
+
const ORIGIN = "https://app.test";
|
|
248
|
+
function buildBundle(assessment) {
|
|
249
|
+
const result = scanResultWithAssessment(assessment, {
|
|
250
|
+
changedPackages: ["express"],
|
|
251
|
+
});
|
|
252
|
+
return buildScanPresentationBundle({ result, pipelineStatus: "done" });
|
|
253
|
+
}
|
|
254
|
+
it("Why section bullets come from assessment.reasoning (ABI 3)", () => {
|
|
255
|
+
const bundle = buildBundle(assessmentExpressAbi3);
|
|
256
|
+
const checkRun = presentGitHubCheckRun(bundle, {
|
|
257
|
+
scanId: SCAN_ID,
|
|
258
|
+
webAppOrigin: ORIGIN,
|
|
259
|
+
});
|
|
260
|
+
const whySection = checkRun.sections.find((s) => s.id === "why" && s.title === "Why");
|
|
261
|
+
expect(whySection).toBeDefined();
|
|
262
|
+
expect(whySection.bullets).toEqual(expect.arrayContaining([
|
|
263
|
+
"express is used in HTTP request handling in this repository via middleware chains.",
|
|
264
|
+
]));
|
|
265
|
+
});
|
|
266
|
+
it("Why section does not contain old generic decision reasoning", () => {
|
|
267
|
+
const bundle = buildBundle(assessmentExpressAbi3);
|
|
268
|
+
const checkRun = presentGitHubCheckRun(bundle, {
|
|
269
|
+
scanId: SCAN_ID,
|
|
270
|
+
webAppOrigin: ORIGIN,
|
|
271
|
+
});
|
|
272
|
+
const whySection = checkRun.sections.find((s) => s.id === "why" && s.title === "Why");
|
|
273
|
+
const bulletText = whySection?.bullets.join(" ") ?? "";
|
|
274
|
+
expect(bulletText).not.toContain("Old generic decision reasoning");
|
|
275
|
+
});
|
|
276
|
+
it("check run summary contains no prohibited vocabulary", () => {
|
|
277
|
+
const result = scanResultWithAssessment(assessmentExpressAbi3, {
|
|
278
|
+
changedPackages: ["express"],
|
|
279
|
+
methodologyVersion: "mergesignal-engine/test",
|
|
280
|
+
});
|
|
281
|
+
const output = buildGitHubCheckRunOutput(result, {
|
|
282
|
+
scanId: SCAN_ID,
|
|
283
|
+
webAppOrigin: ORIGIN,
|
|
284
|
+
});
|
|
285
|
+
const prohibited = [
|
|
286
|
+
"qualityClass",
|
|
287
|
+
"qualityBasis",
|
|
288
|
+
"proofFingerprint",
|
|
289
|
+
"observationId",
|
|
290
|
+
"propagationQualityRank",
|
|
291
|
+
"AssessmentEvidenceBundle",
|
|
292
|
+
];
|
|
293
|
+
for (const term of prohibited) {
|
|
294
|
+
expect(output.summary).not.toContain(term);
|
|
295
|
+
}
|
|
296
|
+
});
|
|
297
|
+
it("Why section respects 3-line limit", () => {
|
|
298
|
+
const bundle = buildBundle(assessmentExpressAbi3);
|
|
299
|
+
const checkRun = presentGitHubCheckRun(bundle, {
|
|
300
|
+
scanId: SCAN_ID,
|
|
301
|
+
webAppOrigin: ORIGIN,
|
|
302
|
+
});
|
|
303
|
+
const whySection = checkRun.sections.find((s) => s.title === "Why");
|
|
304
|
+
if (whySection) {
|
|
305
|
+
expect(whySection.bullets.length).toBeLessThanOrEqual(3);
|
|
306
|
+
}
|
|
307
|
+
});
|
|
308
|
+
});
|
|
309
|
+
// ---------------------------------------------------------------------------
|
|
310
|
+
// End-to-end markdown snapshot — PR comment with ABI 3 fixture
|
|
311
|
+
// ---------------------------------------------------------------------------
|
|
312
|
+
describe("PR comment markdown — ABI 3 end-to-end", () => {
|
|
313
|
+
it("rendered markdown includes repository-specific reasoning", () => {
|
|
314
|
+
const result = scanResultWithAssessment(assessmentExpressAbi3, {
|
|
315
|
+
changedPackages: ["express"],
|
|
316
|
+
});
|
|
317
|
+
const markdown = presentGitHubPrCommentMarkdownFromResult(result);
|
|
318
|
+
expect(markdown).toContain("express is used in HTTP request handling");
|
|
319
|
+
expect(markdown).toContain("Import paths to application entry points");
|
|
320
|
+
});
|
|
321
|
+
it("rendered markdown includes electionSummary", () => {
|
|
322
|
+
const result = scanResultWithAssessment(assessmentExpressAbi3, {
|
|
323
|
+
changedPackages: ["express"],
|
|
324
|
+
});
|
|
325
|
+
const markdown = presentGitHubPrCommentMarkdownFromResult(result);
|
|
326
|
+
expect(markdown).toContain("express was selected as the primary review anchor");
|
|
327
|
+
});
|
|
328
|
+
it("rendered markdown contains no prohibited vocabulary", () => {
|
|
329
|
+
const result = scanResultWithAssessment(assessmentExpressAbi3, {
|
|
330
|
+
changedPackages: ["express"],
|
|
331
|
+
});
|
|
332
|
+
const markdown = presentGitHubPrCommentMarkdownFromResult(result);
|
|
333
|
+
const prohibited = [
|
|
334
|
+
"qualityClass",
|
|
335
|
+
"qualityBasis",
|
|
336
|
+
"proofFingerprint",
|
|
337
|
+
"observationId",
|
|
338
|
+
"propagationQualityRank",
|
|
339
|
+
"AssessmentEvidenceBundle",
|
|
340
|
+
"DenseEvidenceHighlight",
|
|
341
|
+
];
|
|
342
|
+
for (const term of prohibited) {
|
|
343
|
+
expect(markdown).not.toContain(term);
|
|
344
|
+
}
|
|
345
|
+
});
|
|
346
|
+
});
|
|
@@ -1 +1 @@
|
|
|
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,
|
|
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,CAmD5B"}
|
|
@@ -4,7 +4,7 @@ import { projectAssessmentFields } from "../projectAssessmentFields.js";
|
|
|
4
4
|
export function presentGitHubCheckRun(bundle, ctx) {
|
|
5
5
|
const { profile } = bundle;
|
|
6
6
|
const headline = composeHeadline(bundle);
|
|
7
|
-
const
|
|
7
|
+
const assessmentFields = projectAssessmentFields(bundle);
|
|
8
8
|
const actions = composeVerificationActions(bundle, 3);
|
|
9
9
|
const detailsUrl = `${ctx.webAppOrigin.replace(/\/$/, "")}/scan/${ctx.scanId}`;
|
|
10
10
|
const conclusion = profile.status === "safe"
|
|
@@ -22,15 +22,21 @@ export function presentGitHubCheckRun(bundle, ctx) {
|
|
|
22
22
|
bullets: [`${prRiskScore} (${prRiskBandLabelText})`],
|
|
23
23
|
});
|
|
24
24
|
}
|
|
25
|
-
|
|
26
|
-
|
|
25
|
+
// Use assessment.reasoning directly for the Why section (ABI 3).
|
|
26
|
+
// Fall back to compact key points for pre-ABI-3 scan results.
|
|
27
|
+
const reasoningLines = assessmentFields.reasoning.slice(0, 3);
|
|
28
|
+
const whyBullets = reasoningLines.length > 0
|
|
29
|
+
? reasoningLines
|
|
30
|
+
: projectCompactKeyPoints(buildNarrativeChannels(bundle), 3);
|
|
31
|
+
if (whyBullets.length > 0) {
|
|
32
|
+
sections.push({ id: "why", title: "Why", bullets: whyBullets });
|
|
27
33
|
}
|
|
28
34
|
if (actions.length > 0) {
|
|
29
35
|
sections.push({ id: "actions", title: "What to verify", bullets: actions });
|
|
30
36
|
}
|
|
31
37
|
sections.push({ id: "footer", bullets: [`Full scan: ${detailsUrl}`] });
|
|
32
38
|
return {
|
|
33
|
-
...
|
|
39
|
+
...assessmentFields,
|
|
34
40
|
status: profile.status,
|
|
35
41
|
density: profile.density,
|
|
36
42
|
confidence: profile.confidence,
|
|
@@ -1 +1 @@
|
|
|
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,
|
|
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,CAqC7B"}
|
|
@@ -16,6 +16,9 @@ export function presentGitHubPrComment(bundle) {
|
|
|
16
16
|
if (prRiskScore != null && prRiskBandLabelText) {
|
|
17
17
|
introLines.push(`PR Risk: ${prRiskScore} (${prRiskBandLabelText})`);
|
|
18
18
|
}
|
|
19
|
+
const electionSummary = bundle.assessment.reviewFocalPoint.electionSummary;
|
|
20
|
+
if (electionSummary)
|
|
21
|
+
introLines.push(electionSummary);
|
|
19
22
|
for (const line of assessmentFields.reasoning.slice(0, 2)) {
|
|
20
23
|
introLines.push(line);
|
|
21
24
|
}
|
|
@@ -131,6 +131,7 @@ export declare const engineOutputScanResultSchema: z.ZodObject<{
|
|
|
131
131
|
concern: "concern";
|
|
132
132
|
reach: "reach";
|
|
133
133
|
changeSeverity: "changeSeverity";
|
|
134
|
+
repository_importance: "repository_importance";
|
|
134
135
|
role_salience_tiebreak: "role_salience_tiebreak";
|
|
135
136
|
}>;
|
|
136
137
|
evidenceRefs: z.ZodArray<z.ZodString>;
|
|
@@ -142,11 +143,13 @@ export declare const engineOutputScanResultSchema: z.ZodObject<{
|
|
|
142
143
|
concern: "concern";
|
|
143
144
|
reach: "reach";
|
|
144
145
|
changeSeverity: "changeSeverity";
|
|
146
|
+
repository_importance: "repository_importance";
|
|
145
147
|
role_salience_tiebreak: "role_salience_tiebreak";
|
|
146
148
|
}>;
|
|
147
149
|
evidenceRefs: z.ZodArray<z.ZodString>;
|
|
148
150
|
}, z.core.$strip>>;
|
|
149
151
|
}, z.core.$strip>;
|
|
152
|
+
electionSummary: z.ZodOptional<z.ZodString>;
|
|
150
153
|
}, z.core.$strip>;
|
|
151
154
|
reachScope: z.ZodObject<{
|
|
152
155
|
packages: z.ZodArray<z.ZodString>;
|
|
@@ -161,6 +164,7 @@ export declare const engineOutputScanResultSchema: z.ZodObject<{
|
|
|
161
164
|
verificationScope: z.ZodObject<{
|
|
162
165
|
packages: z.ZodArray<z.ZodString>;
|
|
163
166
|
focus: z.ZodArray<z.ZodString>;
|
|
167
|
+
guidance: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
164
168
|
artifactGrounded: z.ZodOptional<z.ZodObject<{
|
|
165
169
|
packages: z.ZodArray<z.ZodString>;
|
|
166
170
|
focus: z.ZodArray<z.ZodString>;
|
|
@@ -199,6 +203,7 @@ export declare const engineOutputScanResultSchema: z.ZodObject<{
|
|
|
199
203
|
rank: z.ZodNumber;
|
|
200
204
|
packages: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
201
205
|
evidenceRefs: z.ZodArray<z.ZodString>;
|
|
206
|
+
context: z.ZodOptional<z.ZodString>;
|
|
202
207
|
}, z.core.$strip>>;
|
|
203
208
|
factors: z.ZodArray<z.ZodString>;
|
|
204
209
|
changeClasses: z.ZodArray<z.ZodEnum<{
|
|
@@ -238,6 +243,8 @@ export declare const engineOutputScanResultSchema: z.ZodObject<{
|
|
|
238
243
|
high_signal_pr: "high_signal_pr";
|
|
239
244
|
}>;
|
|
240
245
|
}, z.core.$strip>;
|
|
246
|
+
reasoning: z.ZodArray<z.ZodString>;
|
|
247
|
+
confidenceRationale: z.ZodString;
|
|
241
248
|
}, z.core.$strip>;
|
|
242
249
|
prRisk: z.ZodObject<{
|
|
243
250
|
score: z.ZodNumber;
|
|
@@ -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;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
|
|
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"}
|