@mergesignal/shared 0.12.2 → 0.13.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/assessment/authoredCommunication.d.ts +30 -0
- package/dist/assessment/authoredCommunication.d.ts.map +1 -0
- package/dist/assessment/authoredCommunication.js +18 -0
- package/dist/assessment/index.d.ts +6 -0
- package/dist/assessment/index.d.ts.map +1 -0
- package/dist/assessment/index.js +5 -0
- package/dist/assessment/literals.d.ts +44 -0
- package/dist/assessment/literals.d.ts.map +1 -0
- package/dist/assessment/literals.js +140 -0
- package/dist/assessment/schema.d.ts +311 -0
- package/dist/assessment/schema.d.ts.map +1 -0
- package/dist/assessment/schema.js +162 -0
- package/dist/assessment/types.d.ts +197 -0
- package/dist/assessment/types.d.ts.map +1 -0
- package/dist/assessment/types.js +1 -0
- package/dist/assessment/version.d.ts +11 -0
- package/dist/assessment/version.d.ts.map +1 -0
- package/dist/assessment/version.js +9 -0
- package/dist/assessmentLabels.d.ts +1 -1
- package/dist/assessmentLabels.d.ts.map +1 -1
- package/dist/assessmentPresentationUtils.d.ts +1 -1
- package/dist/assessmentPresentationUtils.d.ts.map +1 -1
- package/dist/assessmentProjection.d.ts +1 -1
- package/dist/assessmentProjection.d.ts.map +1 -1
- package/dist/deriveScanNarrative.d.ts.map +1 -1
- package/dist/deriveScanNarrative.js +2 -1
- package/dist/fixtures/assessmentFixtures.d.ts +1 -1
- package/dist/fixtures/assessmentScopeFixtures.d.ts +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/lockfileEvidence.d.ts +22 -0
- package/dist/lockfileEvidence.d.ts.map +1 -0
- package/dist/lockfileEvidence.js +32 -0
- package/dist/presentation/dto/assessmentPresentationFields.d.ts +1 -1
- package/dist/presentation/dto/assessmentPresentationFields.d.ts.map +1 -1
- package/dist/presentation/orchestration/buildScanPresentationBundle.d.ts.map +1 -1
- package/dist/presentation/orchestration/buildScanPresentationBundle.js +2 -1
- package/dist/presentation/orchestration/scanPresentationBundle.d.ts +2 -1
- package/dist/presentation/orchestration/scanPresentationBundle.d.ts.map +1 -1
- package/dist/presentation/profile/buildProfileFromAssessment.d.ts +1 -1
- package/dist/presentation/profile/buildProfileFromAssessment.d.ts.map +1 -1
- package/dist/presentation/profile/buildProfileFromAssessment.js +13 -5
- package/dist/repoIntelligenceSchema.d.ts +5 -5
- package/dist/scanResultSchema.d.ts +6 -6
- package/dist/scanResultSchema.js +1 -1
- package/dist/types.d.ts +6 -2
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -2
- package/dist/actionsStepSummary.test.d.ts +0 -2
- package/dist/actionsStepSummary.test.d.ts.map +0 -1
- package/dist/actionsStepSummary.test.js +0 -53
- package/dist/assessmentProjection.verificationChannel.test.d.ts +0 -2
- package/dist/assessmentProjection.verificationChannel.test.d.ts.map +0 -1
- package/dist/assessmentProjection.verificationChannel.test.js +0 -110
- package/dist/deriveScanNarrative.test.d.ts +0 -2
- package/dist/deriveScanNarrative.test.d.ts.map +0 -1
- package/dist/deriveScanNarrative.test.js +0 -274
- package/dist/engineWireRegression.test.d.ts +0 -2
- package/dist/engineWireRegression.test.d.ts.map +0 -1
- package/dist/engineWireRegression.test.js +0 -77
- package/dist/fixtures/engineAbi4Fixtures.d.ts +0 -16
- package/dist/fixtures/engineAbi4Fixtures.d.ts.map +0 -1
- package/dist/fixtures/engineAbi4Fixtures.js +0 -26
- package/dist/fixtures/legacyEngineRepoIntelligence.d.ts +0 -28
- package/dist/fixtures/legacyEngineRepoIntelligence.d.ts.map +0 -1
- package/dist/fixtures/legacyEngineRepoIntelligence.js +0 -28
- package/dist/fixtures/repoIntelligenceFixtures.d.ts +0 -8
- package/dist/fixtures/repoIntelligenceFixtures.d.ts.map +0 -1
- package/dist/fixtures/repoIntelligenceFixtures.js +0 -123
- package/dist/fixtures/repoIntelligenceTestHelpers.d.ts +0 -5
- package/dist/fixtures/repoIntelligenceTestHelpers.d.ts.map +0 -1
- package/dist/fixtures/repoIntelligenceTestHelpers.js +0 -28
- package/dist/formatInsight.test.d.ts +0 -2
- package/dist/formatInsight.test.d.ts.map +0 -1
- package/dist/formatInsight.test.js +0 -102
- package/dist/narrativeParity.test.d.ts +0 -2
- package/dist/narrativeParity.test.d.ts.map +0 -1
- package/dist/narrativeParity.test.js +0 -35
- package/dist/narrativePresentation.test.d.ts +0 -2
- package/dist/narrativePresentation.test.d.ts.map +0 -1
- package/dist/narrativePresentation.test.js +0 -54
- package/dist/normalizeGeneratedText.test.d.ts +0 -2
- package/dist/normalizeGeneratedText.test.d.ts.map +0 -1
- package/dist/normalizeGeneratedText.test.js +0 -18
- package/dist/prRiskBand.test.d.ts +0 -2
- package/dist/prRiskBand.test.d.ts.map +0 -1
- package/dist/prRiskBand.test.js +0 -68
- package/dist/prRiskWire.test.d.ts +0 -2
- package/dist/prRiskWire.test.d.ts.map +0 -1
- package/dist/prRiskWire.test.js +0 -106
- package/dist/prRiskWiringRegression.test.d.ts +0 -2
- package/dist/prRiskWiringRegression.test.d.ts.map +0 -1
- package/dist/prRiskWiringRegression.test.js +0 -102
- package/dist/presentation/abi3Expression.test.d.ts +0 -13
- package/dist/presentation/abi3Expression.test.d.ts.map +0 -1
- package/dist/presentation/abi3Expression.test.js +0 -392
- package/dist/presentation/buildGitHubCheckRunOutput.test.d.ts +0 -2
- package/dist/presentation/buildGitHubCheckRunOutput.test.d.ts.map +0 -1
- package/dist/presentation/buildGitHubCheckRunOutput.test.js +0 -163
- package/dist/presentation/bundleAccessorParity.test.d.ts +0 -9
- package/dist/presentation/bundleAccessorParity.test.d.ts.map +0 -1
- package/dist/presentation/bundleAccessorParity.test.js +0 -126
- package/dist/presentation/cliParity.test.d.ts +0 -2
- package/dist/presentation/cliParity.test.d.ts.map +0 -1
- package/dist/presentation/cliParity.test.js +0 -49
- package/dist/presentation/compose/narrativeChannels.test.d.ts +0 -2
- package/dist/presentation/compose/narrativeChannels.test.d.ts.map +0 -1
- package/dist/presentation/compose/narrativeChannels.test.js +0 -42
- package/dist/presentation/decisionSurface.test.d.ts +0 -2
- package/dist/presentation/decisionSurface.test.d.ts.map +0 -1
- package/dist/presentation/decisionSurface.test.js +0 -290
- package/dist/presentation/fixtures/dashboardCardGolden.test.d.ts +0 -2
- package/dist/presentation/fixtures/dashboardCardGolden.test.d.ts.map +0 -1
- package/dist/presentation/fixtures/dashboardCardGolden.test.js +0 -38
- package/dist/presentation/fixtures/presentationPersonaFixtures.d.ts +0 -11
- package/dist/presentation/fixtures/presentationPersonaFixtures.d.ts.map +0 -1
- package/dist/presentation/fixtures/presentationPersonaFixtures.js +0 -208
- package/dist/presentation/fixtures/scanResultFixtures.d.ts +0 -5
- package/dist/presentation/fixtures/scanResultFixtures.d.ts.map +0 -1
- package/dist/presentation/fixtures/scanResultFixtures.js +0 -123
- package/dist/presentation/intent/postureVocabularyGuard.test.d.ts +0 -2
- package/dist/presentation/intent/postureVocabularyGuard.test.d.ts.map +0 -1
- package/dist/presentation/intent/postureVocabularyGuard.test.js +0 -23
- package/dist/presentation/orchestration/buildScanPresentationBundle.test.d.ts +0 -2
- package/dist/presentation/orchestration/buildScanPresentationBundle.test.d.ts.map +0 -1
- package/dist/presentation/orchestration/buildScanPresentationBundle.test.js +0 -99
- package/dist/presentation/presentation.test.d.ts +0 -2
- package/dist/presentation/presentation.test.d.ts.map +0 -1
- package/dist/presentation/presentation.test.js +0 -126
- package/dist/presentation/presentationPersonas.test.d.ts +0 -2
- package/dist/presentation/presentationPersonas.test.d.ts.map +0 -1
- package/dist/presentation/presentationPersonas.test.js +0 -164
- package/dist/presentation/surfaceParity.test.d.ts +0 -2
- package/dist/presentation/surfaceParity.test.d.ts.map +0 -1
- package/dist/presentation/surfaceParity.test.js +0 -156
- package/dist/presentation/verificationChannelParity.test.d.ts +0 -2
- package/dist/presentation/verificationChannelParity.test.d.ts.map +0 -1
- package/dist/presentation/verificationChannelParity.test.js +0 -57
- package/dist/productMessaging.test.d.ts +0 -2
- package/dist/productMessaging.test.d.ts.map +0 -1
- package/dist/productMessaging.test.js +0 -97
- package/dist/repoIntelligenceSchema.contract.test.d.ts +0 -2
- package/dist/repoIntelligenceSchema.contract.test.d.ts.map +0 -1
- package/dist/repoIntelligenceSchema.contract.test.js +0 -51
- package/dist/repoIntelligenceSemantics.test.d.ts +0 -2
- package/dist/repoIntelligenceSemantics.test.d.ts.map +0 -1
- package/dist/repoIntelligenceSemantics.test.js +0 -63
- package/dist/repoIntelligenceValidation.persist.test.d.ts +0 -2
- package/dist/repoIntelligenceValidation.persist.test.d.ts.map +0 -1
- package/dist/repoIntelligenceValidation.persist.test.js +0 -44
- package/dist/riskSignals.test.d.ts +0 -2
- package/dist/riskSignals.test.d.ts.map +0 -1
- package/dist/riskSignals.test.js +0 -32
- package/dist/riskVocabulary.test.d.ts +0 -2
- package/dist/riskVocabulary.test.d.ts.map +0 -1
- package/dist/riskVocabulary.test.js +0 -14
- package/dist/scanPresentationBundle.golden.test.d.ts +0 -2
- package/dist/scanPresentationBundle.golden.test.d.ts.map +0 -1
- package/dist/scanPresentationBundle.golden.test.js +0 -78
- package/dist/scanResultSchema.test.d.ts +0 -2
- package/dist/scanResultSchema.test.d.ts.map +0 -1
- package/dist/scanResultSchema.test.js +0 -162
- package/dist/scanSurfaceCopy.test.d.ts +0 -2
- package/dist/scanSurfaceCopy.test.d.ts.map +0 -1
- package/dist/scanSurfaceCopy.test.js +0 -14
- package/dist/selectTopAffectedAreas.test.d.ts +0 -2
- package/dist/selectTopAffectedAreas.test.d.ts.map +0 -1
- package/dist/selectTopAffectedAreas.test.js +0 -179
- package/dist/trustedScanGuards.test.d.ts +0 -2
- package/dist/trustedScanGuards.test.d.ts.map +0 -1
- package/dist/trustedScanGuards.test.js +0 -151
|
@@ -1,126 +0,0 @@
|
|
|
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
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"cliParity.test.d.ts","sourceRoot":"","sources":["../../src/presentation/cliParity.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,49 +0,0 @@
|
|
|
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
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"narrativeChannels.test.d.ts","sourceRoot":"","sources":["../../../src/presentation/compose/narrativeChannels.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from "vitest";
|
|
2
|
-
import { buildScanPresentationBundle } from "../orchestration/buildScanPresentationBundle.js";
|
|
3
|
-
import { scanResultFastifyRuntime } from "../fixtures/scanResultFixtures.js";
|
|
4
|
-
import { buildNarrativeChannels, projectCompactKeyPoints, } from "./narrativeChannels.js";
|
|
5
|
-
import { presentDashboardCard } from "../presenters/presentDashboardCard.js";
|
|
6
|
-
describe("buildNarrativeChannels", () => {
|
|
7
|
-
it("fastify: areas in scopeAreas only, blast in evidence only, not in insights", () => {
|
|
8
|
-
const bundle = buildScanPresentationBundle({
|
|
9
|
-
result: scanResultFastifyRuntime,
|
|
10
|
-
pipelineStatus: "done",
|
|
11
|
-
});
|
|
12
|
-
const channels = buildNarrativeChannels(bundle);
|
|
13
|
-
const insightText = channels.insights.join(" ");
|
|
14
|
-
expect(insightText).not.toMatch(/Affected areas:/i);
|
|
15
|
-
expect(insightText).not.toMatch(/Blast radius is/i);
|
|
16
|
-
expect(channels.scopeAreas.length).toBeGreaterThan(0);
|
|
17
|
-
expect(channels.evidence.some((r) => r.label === "Blast radius")).toBe(true);
|
|
18
|
-
expect(channels.evidence.some((r) => r.label === "Runtime")).toBe(false);
|
|
19
|
-
});
|
|
20
|
-
it("projectCompactKeyPoints merges channels for single-column surfaces", () => {
|
|
21
|
-
const bundle = buildScanPresentationBundle({
|
|
22
|
-
result: scanResultFastifyRuntime,
|
|
23
|
-
pipelineStatus: "done",
|
|
24
|
-
});
|
|
25
|
-
const channels = buildNarrativeChannels(bundle);
|
|
26
|
-
const compact = projectCompactKeyPoints(channels, 5);
|
|
27
|
-
expect(compact.some((p) => /Affected areas:/i.test(p))).toBe(true);
|
|
28
|
-
expect(compact.some((p) => /Blast radius is/i.test(p))).toBe(true);
|
|
29
|
-
});
|
|
30
|
-
it("presentDashboardCard does not duplicate areas across insights and scopeAreas", () => {
|
|
31
|
-
const bundle = buildScanPresentationBundle({
|
|
32
|
-
result: scanResultFastifyRuntime,
|
|
33
|
-
pipelineStatus: "done",
|
|
34
|
-
});
|
|
35
|
-
const card = presentDashboardCard(bundle);
|
|
36
|
-
const insightText = card.insights.join(" ");
|
|
37
|
-
expect(insightText).not.toMatch(/Affected areas:/i);
|
|
38
|
-
expect(card.scopeAreas?.length).toBeGreaterThan(0);
|
|
39
|
-
expect(card.verdict?.scopeLabel).toBeTruthy();
|
|
40
|
-
expect(card.verification.every((v) => v.startsWith("Verify"))).toBe(true);
|
|
41
|
-
});
|
|
42
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"decisionSurface.test.d.ts","sourceRoot":"","sources":["../../src/presentation/decisionSurface.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,290 +0,0 @@
|
|
|
1
|
-
import { extractAuthoredCommunication } from "@mergesignal/contracts";
|
|
2
|
-
import { describe, expect, it } from "vitest";
|
|
3
|
-
import { minimalReviewFocalPoint, reachScopeFor, verificationScopeFor, withAssessmentScope, } from "../fixtures/assessmentScopeFixtures.js";
|
|
4
|
-
import { buildScanPresentationBundle } from "./orchestration/buildScanPresentationBundle.js";
|
|
5
|
-
// ─── Vocabulary firewall ──────────────────────────────────────────────────────
|
|
6
|
-
/** Engine vocabulary that must never appear in any developer-facing authored string. */
|
|
7
|
-
const ENGINE_VOCABULARY = [
|
|
8
|
-
"constraint_satisfiability",
|
|
9
|
-
"lockfile_integrity",
|
|
10
|
-
"type_surface_compatibility",
|
|
11
|
-
"export_resolution",
|
|
12
|
-
"peer_dependency",
|
|
13
|
-
"engine_constraint",
|
|
14
|
-
"no_impact_proven",
|
|
15
|
-
"proof_pass",
|
|
16
|
-
"bounded_verify",
|
|
17
|
-
"representative_precision_only",
|
|
18
|
-
"architectural_precision_only",
|
|
19
|
-
"clearanceEnvelope",
|
|
20
|
-
"coverageClass",
|
|
21
|
-
"precisionLevel",
|
|
22
|
-
"proofArtifact",
|
|
23
|
-
"packageOutcome",
|
|
24
|
-
"qualityClass",
|
|
25
|
-
"qualityBasis",
|
|
26
|
-
"proofFingerprint",
|
|
27
|
-
"observationId",
|
|
28
|
-
"dimension_verification",
|
|
29
|
-
];
|
|
30
|
-
// ─── Fixture helpers ──────────────────────────────────────────────────────────
|
|
31
|
-
function scanResultWith(assessment) {
|
|
32
|
-
return {
|
|
33
|
-
totalScore: 70,
|
|
34
|
-
layerScores: {
|
|
35
|
-
security: 70,
|
|
36
|
-
maintainability: 70,
|
|
37
|
-
ecosystem: 70,
|
|
38
|
-
upgradeImpact: 70,
|
|
39
|
-
},
|
|
40
|
-
findings: [],
|
|
41
|
-
generatedAt: "2026-01-01T00:00:00Z",
|
|
42
|
-
changedPackages: assessment.reviewFocalPoint.anchors,
|
|
43
|
-
methodologyVersion: "mergesignal-engine/test",
|
|
44
|
-
assessment,
|
|
45
|
-
decision: {
|
|
46
|
-
recommendation: "needs_review",
|
|
47
|
-
confidence: "medium",
|
|
48
|
-
reasoning: [],
|
|
49
|
-
},
|
|
50
|
-
insights: [],
|
|
51
|
-
};
|
|
52
|
-
}
|
|
53
|
-
function assessmentWithTrustLine() {
|
|
54
|
-
return withAssessmentScope({
|
|
55
|
-
posture: "safe",
|
|
56
|
-
confidence: "high",
|
|
57
|
-
primaryConcern: null,
|
|
58
|
-
concerns: [],
|
|
59
|
-
factors: [],
|
|
60
|
-
changeClasses: [],
|
|
61
|
-
presentation: {
|
|
62
|
-
narrativeIntensity: "standard",
|
|
63
|
-
reachVisibility: "contextual",
|
|
64
|
-
verificationIntensity: "none",
|
|
65
|
-
insightEmissionFloor: "full",
|
|
66
|
-
reportMode: "high_signal_pr",
|
|
67
|
-
},
|
|
68
|
-
reasoning: [
|
|
69
|
-
"All peer dependency constraints verified — no runtime breakage confirmed.",
|
|
70
|
-
"Export compatibility proven unused in this repository.",
|
|
71
|
-
],
|
|
72
|
-
confidenceRationale: "Confidence is high: all assessed dimensions were verified by deterministic proof.",
|
|
73
|
-
}, {
|
|
74
|
-
reviewFocalPoint: minimalReviewFocalPoint(["express"]),
|
|
75
|
-
reachScope: reachScopeFor(["express"]),
|
|
76
|
-
verificationScope: verificationScopeFor(["express"]),
|
|
77
|
-
});
|
|
78
|
-
}
|
|
79
|
-
function assessmentWithElectionSummary() {
|
|
80
|
-
return withAssessmentScope({
|
|
81
|
-
posture: "needs_review",
|
|
82
|
-
confidence: "medium",
|
|
83
|
-
primaryConcern: "confirmed_runtime_usage",
|
|
84
|
-
concerns: [
|
|
85
|
-
{
|
|
86
|
-
kind: "confirmed_runtime_usage",
|
|
87
|
-
rank: 1,
|
|
88
|
-
packages: ["fastify"],
|
|
89
|
-
evidenceRefs: [],
|
|
90
|
-
context: "Runtime usage: `fastify` — used in HTTP request handling.",
|
|
91
|
-
},
|
|
92
|
-
],
|
|
93
|
-
factors: ["confirmed_runtime_usage"],
|
|
94
|
-
changeClasses: ["runtime_upgrade"],
|
|
95
|
-
presentation: {
|
|
96
|
-
narrativeIntensity: "standard",
|
|
97
|
-
reachVisibility: "contextual",
|
|
98
|
-
verificationIntensity: "required",
|
|
99
|
-
insightEmissionFloor: "full",
|
|
100
|
-
reportMode: "high_signal_pr",
|
|
101
|
-
},
|
|
102
|
-
reasoning: [
|
|
103
|
-
"fastify is used in HTTP request handling in this repository.",
|
|
104
|
-
],
|
|
105
|
-
confidenceRationale: "Confidence is medium: runtime usage was observed but proof coverage is representative.",
|
|
106
|
-
notAffectedLine: null,
|
|
107
|
-
resolutionLine: null,
|
|
108
|
-
}, {
|
|
109
|
-
reviewFocalPoint: {
|
|
110
|
-
episodeShape: "single_anchor",
|
|
111
|
-
anchors: ["fastify"],
|
|
112
|
-
electionSummary: "`fastify` was selected as the review anchor over `fastify-plugin` due to higher runtime reach.",
|
|
113
|
-
election: {
|
|
114
|
-
grounding: [
|
|
115
|
-
{
|
|
116
|
-
packageName: "fastify",
|
|
117
|
-
reason: "highest_runtime_reach",
|
|
118
|
-
decidedBy: "reach",
|
|
119
|
-
evidenceRefs: [],
|
|
120
|
-
},
|
|
121
|
-
],
|
|
122
|
-
exclusions: [
|
|
123
|
-
{
|
|
124
|
-
packageName: "fastify-plugin",
|
|
125
|
-
reason: "lower_runtime_reach",
|
|
126
|
-
lostOn: "reach",
|
|
127
|
-
evidenceRefs: [],
|
|
128
|
-
},
|
|
129
|
-
],
|
|
130
|
-
},
|
|
131
|
-
},
|
|
132
|
-
reachScope: reachScopeFor(["fastify"]),
|
|
133
|
-
verificationScope: verificationScopeFor(["fastify"]),
|
|
134
|
-
});
|
|
135
|
-
}
|
|
136
|
-
function assessmentUncontestedElection() {
|
|
137
|
-
return withAssessmentScope({
|
|
138
|
-
posture: "needs_review",
|
|
139
|
-
confidence: "medium",
|
|
140
|
-
primaryConcern: "confirmed_runtime_usage",
|
|
141
|
-
concerns: [],
|
|
142
|
-
factors: ["confirmed_runtime_usage"],
|
|
143
|
-
changeClasses: ["runtime_upgrade"],
|
|
144
|
-
presentation: {
|
|
145
|
-
narrativeIntensity: "standard",
|
|
146
|
-
reachVisibility: "contextual",
|
|
147
|
-
verificationIntensity: "required",
|
|
148
|
-
insightEmissionFloor: "full",
|
|
149
|
-
reportMode: "high_signal_pr",
|
|
150
|
-
},
|
|
151
|
-
reasoning: ["express is used in HTTP request handling."],
|
|
152
|
-
confidenceRationale: "Confidence is high: runtime usage was directly observed.",
|
|
153
|
-
}, {
|
|
154
|
-
reviewFocalPoint: minimalReviewFocalPoint(["express"]),
|
|
155
|
-
reachScope: reachScopeFor(["express"]),
|
|
156
|
-
verificationScope: verificationScopeFor(["express"]),
|
|
157
|
-
});
|
|
158
|
-
}
|
|
159
|
-
function assessmentWithQ8Q9() {
|
|
160
|
-
return withAssessmentScope({
|
|
161
|
-
posture: "needs_review",
|
|
162
|
-
confidence: "medium",
|
|
163
|
-
primaryConcern: "confirmed_runtime_usage",
|
|
164
|
-
concerns: [],
|
|
165
|
-
factors: ["confirmed_runtime_usage"],
|
|
166
|
-
changeClasses: ["runtime_upgrade"],
|
|
167
|
-
outcome: "bounded_verify",
|
|
168
|
-
presentation: {
|
|
169
|
-
narrativeIntensity: "standard",
|
|
170
|
-
reachVisibility: "contextual",
|
|
171
|
-
verificationIntensity: "required",
|
|
172
|
-
insightEmissionFloor: "full",
|
|
173
|
-
reportMode: "high_signal_pr",
|
|
174
|
-
},
|
|
175
|
-
reasoning: ["Automation stopped before all dimensions were verified."],
|
|
176
|
-
confidenceRationale: "Confidence is medium: bounded verification is required.",
|
|
177
|
-
notAffectedLine: "No repository code paths are affected by export compatibility — this dimension is outside the review scope.",
|
|
178
|
-
resolutionLine: "A passing automated verification for this dimension would make this deterministic.",
|
|
179
|
-
}, {
|
|
180
|
-
reviewFocalPoint: minimalReviewFocalPoint(["express"]),
|
|
181
|
-
reachScope: reachScopeFor(["express"]),
|
|
182
|
-
verificationScope: {
|
|
183
|
-
packages: ["express"],
|
|
184
|
-
focus: [],
|
|
185
|
-
guidance: ["Verify route handler at `src/server.ts:42`."],
|
|
186
|
-
},
|
|
187
|
-
});
|
|
188
|
-
}
|
|
189
|
-
// ─── V1 bundle transport ──────────────────────────────────────────────────────
|
|
190
|
-
describe("decision surface contract (V1) — bundle transport", () => {
|
|
191
|
-
it("trustLine carries confidenceRationale verbatim from assessment", () => {
|
|
192
|
-
const assessment = assessmentWithTrustLine();
|
|
193
|
-
const bundle = buildScanPresentationBundle({
|
|
194
|
-
result: scanResultWith(assessment),
|
|
195
|
-
pipelineStatus: "done",
|
|
196
|
-
});
|
|
197
|
-
expect(bundle).not.toBeNull();
|
|
198
|
-
expect(bundle.trustLine).toBe(assessment.confidenceRationale);
|
|
199
|
-
});
|
|
200
|
-
it("whyThisPackageLine carries electionSummary verbatim when present", () => {
|
|
201
|
-
const assessment = assessmentWithElectionSummary();
|
|
202
|
-
const bundle = buildScanPresentationBundle({
|
|
203
|
-
result: scanResultWith(assessment),
|
|
204
|
-
pipelineStatus: "done",
|
|
205
|
-
});
|
|
206
|
-
expect(bundle.whyThisPackageLine).toBe(assessment.reviewFocalPoint.electionSummary);
|
|
207
|
-
});
|
|
208
|
-
it("whyThisPackageLine is null when electionSummary is absent", () => {
|
|
209
|
-
const assessment = assessmentUncontestedElection();
|
|
210
|
-
const bundle = buildScanPresentationBundle({
|
|
211
|
-
result: scanResultWith(assessment),
|
|
212
|
-
pipelineStatus: "done",
|
|
213
|
-
});
|
|
214
|
-
expect(bundle.whyThisPackageLine).toBeNull();
|
|
215
|
-
});
|
|
216
|
-
it("reasoningLines and guidanceLines carry assessment arrays verbatim", () => {
|
|
217
|
-
const assessment = assessmentWithQ8Q9();
|
|
218
|
-
const bundle = buildScanPresentationBundle({
|
|
219
|
-
result: scanResultWith(assessment),
|
|
220
|
-
pipelineStatus: "done",
|
|
221
|
-
});
|
|
222
|
-
expect(bundle.reasoningLines).toEqual(assessment.reasoning);
|
|
223
|
-
expect(bundle.guidanceLines).toEqual(assessment.verificationScope.guidance ?? []);
|
|
224
|
-
});
|
|
225
|
-
it("notAffectedLine and resolutionLine survive parse and transport (Q8/Q9)", () => {
|
|
226
|
-
const assessment = assessmentWithQ8Q9();
|
|
227
|
-
const bundle = buildScanPresentationBundle({
|
|
228
|
-
result: scanResultWith(assessment),
|
|
229
|
-
pipelineStatus: "done",
|
|
230
|
-
});
|
|
231
|
-
expect(bundle.notAffectedLine).toBe(assessment.notAffectedLine);
|
|
232
|
-
expect(bundle.resolutionLine).toBe(assessment.resolutionLine);
|
|
233
|
-
});
|
|
234
|
-
it("concernContextLines carries concerns[].context verbatim", () => {
|
|
235
|
-
const assessment = assessmentWithElectionSummary();
|
|
236
|
-
const bundle = buildScanPresentationBundle({
|
|
237
|
-
result: scanResultWith(assessment),
|
|
238
|
-
pipelineStatus: "done",
|
|
239
|
-
});
|
|
240
|
-
expect(bundle.concernContextLines).toEqual([
|
|
241
|
-
"Runtime usage: `fastify` — used in HTTP request handling.",
|
|
242
|
-
]);
|
|
243
|
-
});
|
|
244
|
-
it("public bundle accessors match extractAuthoredCommunication", () => {
|
|
245
|
-
const assessment = assessmentWithQ8Q9();
|
|
246
|
-
const normalized = assessment;
|
|
247
|
-
const expected = extractAuthoredCommunication(normalized);
|
|
248
|
-
const bundle = buildScanPresentationBundle({
|
|
249
|
-
result: scanResultWith(assessment),
|
|
250
|
-
pipelineStatus: "done",
|
|
251
|
-
});
|
|
252
|
-
expect(bundle.trustLine).toBe(expected.trustLine);
|
|
253
|
-
expect(bundle.whyThisPackageLine).toBe(expected.whyThisPackageLine);
|
|
254
|
-
expect(bundle.notAffectedLine).toBe(expected.notAffectedLine);
|
|
255
|
-
expect(bundle.resolutionLine).toBe(expected.resolutionLine);
|
|
256
|
-
expect(bundle.reasoningLines).toEqual(expected.reasoningLines);
|
|
257
|
-
expect(bundle.guidanceLines).toEqual(expected.guidanceLines);
|
|
258
|
-
expect(bundle.concernContextLines).toEqual(expected.concernContextLines);
|
|
259
|
-
});
|
|
260
|
-
});
|
|
261
|
-
// ─── Vocabulary firewall ──────────────────────────────────────────────────────
|
|
262
|
-
describe("decision surface contract (V1) — vocabulary firewall on accessors", () => {
|
|
263
|
-
function assertNoEngineVocabulary(strings, context) {
|
|
264
|
-
for (const token of ENGINE_VOCABULARY) {
|
|
265
|
-
for (const str of strings) {
|
|
266
|
-
if (!str)
|
|
267
|
-
continue;
|
|
268
|
-
expect(str, `${context}: must not contain engine token "${token}"`).not.toContain(token);
|
|
269
|
-
}
|
|
270
|
-
}
|
|
271
|
-
}
|
|
272
|
-
it("bundle accessors carry no engine vocabulary", () => {
|
|
273
|
-
const assessment = assessmentWithQ8Q9();
|
|
274
|
-
const bundle = buildScanPresentationBundle({
|
|
275
|
-
result: scanResultWith(assessment),
|
|
276
|
-
pipelineStatus: "done",
|
|
277
|
-
});
|
|
278
|
-
assertNoEngineVocabulary([
|
|
279
|
-
bundle.trustLine,
|
|
280
|
-
bundle.whyThisPackageLine,
|
|
281
|
-
bundle.notAffectedLine,
|
|
282
|
-
bundle.resolutionLine,
|
|
283
|
-
...bundle.reasoningLines,
|
|
284
|
-
...bundle.guidanceLines,
|
|
285
|
-
...bundle.concernContextLines,
|
|
286
|
-
], "bundle accessors");
|
|
287
|
-
});
|
|
288
|
-
});
|
|
289
|
-
// V3 surface delivery (Dashboard, Scan Details) is intentionally excluded from V1 graduation.
|
|
290
|
-
// See presentDashboardCard / presentScanDetails adoption in V3 Surface Adoption roadmap.
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"dashboardCardGolden.test.d.ts","sourceRoot":"","sources":["../../../src/presentation/fixtures/dashboardCardGolden.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import { readFileSync } from "node:fs";
|
|
2
|
-
import { dirname, join } from "node:path";
|
|
3
|
-
import { fileURLToPath } from "node:url";
|
|
4
|
-
import { describe, expect, it } from "vitest";
|
|
5
|
-
import { buildScanCardPresentation } from "../orchestration/buildScanCardPresentation.js";
|
|
6
|
-
import { scanResultBullmq, scanResultEslint, scanResultFastifyRuntime, scanResultLimitedContext, scanResultMixedTypescriptFastify, scanResultNextAuth, scanResultPrettier, scanResultTypescriptPatch, scanResultUnknownSafe, scanResultVitest, } from "./presentationPersonaFixtures.js";
|
|
7
|
-
const goldenPath = join(dirname(fileURLToPath(import.meta.url)), "dashboardCardGolden.json");
|
|
8
|
-
const golden = JSON.parse(readFileSync(goldenPath, "utf8"));
|
|
9
|
-
const personaCases = [
|
|
10
|
-
{ key: "typescriptPatch", result: scanResultTypescriptPatch },
|
|
11
|
-
{ key: "eslint", result: scanResultEslint },
|
|
12
|
-
{ key: "prettier", result: scanResultPrettier },
|
|
13
|
-
{ key: "vitest", result: scanResultVitest },
|
|
14
|
-
{ key: "fastifyRuntime", result: scanResultFastifyRuntime },
|
|
15
|
-
{ key: "nextAuth", result: scanResultNextAuth },
|
|
16
|
-
{ key: "bullmq", result: scanResultBullmq },
|
|
17
|
-
{ key: "limitedContext", result: scanResultLimitedContext },
|
|
18
|
-
{ key: "unknownSafe", result: scanResultUnknownSafe },
|
|
19
|
-
{ key: "mixedTypescriptFastify", result: scanResultMixedTypescriptFastify },
|
|
20
|
-
];
|
|
21
|
-
describe("dashboardCardGolden fixtures", () => {
|
|
22
|
-
for (const { key, result } of personaCases) {
|
|
23
|
-
it(`matches live ${key} card`, () => {
|
|
24
|
-
const live = buildScanCardPresentation({
|
|
25
|
-
result,
|
|
26
|
-
pipelineStatus: "done",
|
|
27
|
-
});
|
|
28
|
-
expect(live).toEqual(golden[key]);
|
|
29
|
-
});
|
|
30
|
-
}
|
|
31
|
-
it("fastify golden has deduplicated channels", () => {
|
|
32
|
-
const card = golden.fastifyRuntime;
|
|
33
|
-
const insightText = card.insights.join(" ");
|
|
34
|
-
expect(insightText).not.toMatch(/Affected areas:/i);
|
|
35
|
-
expect(card.scopeAreas?.length).toBeGreaterThan(0);
|
|
36
|
-
expect(card.evidenceChips?.some((e) => e.label === "Blast radius")).toBe(true);
|
|
37
|
-
});
|
|
38
|
-
});
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import type { ScanResult } from "../../types.js";
|
|
2
|
-
import { scanResultFastifyRuntime, scanResultLimitedContext, scanResultTypescriptPatch } from "./scanResultFixtures.js";
|
|
3
|
-
export declare const scanResultEslint: ScanResult;
|
|
4
|
-
export declare const scanResultPrettier: ScanResult;
|
|
5
|
-
export declare const scanResultVitest: ScanResult;
|
|
6
|
-
export declare const scanResultNextAuth: ScanResult;
|
|
7
|
-
export declare const scanResultBullmq: ScanResult;
|
|
8
|
-
export declare const scanResultUnknownSafe: ScanResult;
|
|
9
|
-
export declare const scanResultMixedTypescriptFastify: ScanResult;
|
|
10
|
-
export { scanResultFastifyRuntime, scanResultLimitedContext, scanResultTypescriptPatch, };
|
|
11
|
-
//# sourceMappingURL=presentationPersonaFixtures.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"presentationPersonaFixtures.d.ts","sourceRoot":"","sources":["../../../src/presentation/fixtures/presentationPersonaFixtures.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAmBjD,OAAO,EACL,wBAAwB,EACxB,wBAAwB,EACxB,yBAAyB,EAC1B,MAAM,yBAAyB,CAAC;AA+KjC,eAAO,MAAM,gBAAgB,EAAE,UAG7B,CAAC;AAEH,eAAO,MAAM,kBAAkB,EAAE,UAShC,CAAC;AAEF,eAAO,MAAM,gBAAgB,EAAE,UAG7B,CAAC;AAEH,eAAO,MAAM,kBAAkB,EAAE,UAI/B,CAAC;AAEH,eAAO,MAAM,gBAAgB,EAAE,UAa7B,CAAC;AAEH,eAAO,MAAM,qBAAqB,EAAE,UAMnC,CAAC;AAEF,eAAO,MAAM,gCAAgC,EAAE,UAO9C,CAAC;AAEF,OAAO,EACL,wBAAwB,EACxB,wBAAwB,EACxB,yBAAyB,GAC1B,CAAC"}
|