@mergesignal/shared 0.12.1 → 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/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/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/orchestration/buildScanPresentationBundle.d.ts.map +1 -1
- package/dist/presentation/orchestration/buildScanPresentationBundle.js +3 -1
- package/dist/presentation/orchestration/scanPresentationBundle.d.ts +4 -4
- package/dist/presentation/orchestration/scanPresentationBundle.d.ts.map +1 -1
- package/dist/scanResultSchema.d.ts +158 -0
- package/dist/scanResultSchema.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -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":"decisionSurface.test.d.ts","sourceRoot":"","sources":["../../src/presentation/decisionSurface.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,290 @@
|
|
|
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 +1 @@
|
|
|
1
|
-
{"version":3,"file":"buildScanPresentationBundle.d.ts","sourceRoot":"","sources":["../../../src/presentation/orchestration/buildScanPresentationBundle.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"buildScanPresentationBundle.d.ts","sourceRoot":"","sources":["../../../src/presentation/orchestration/buildScanPresentationBundle.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAEtD,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AAE1E,MAAM,MAAM,gCAAgC,GAAG;IAC7C,MAAM,EAAE,UAAU,CAAC;IACnB,cAAc,EAAE,cAAc,CAAC;IAC/B,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,2BAA2B,CACzC,KAAK,EAAE,gCAAgC,GACtC,sBAAsB,GAAG,IAAI,CA8B/B"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { parseAssessmentOrThrow } from "@mergesignal/contracts";
|
|
1
|
+
import { extractAuthoredCommunication, parseAssessmentOrThrow, } from "@mergesignal/contracts";
|
|
2
2
|
import { toPublicPresentation } from "../../assessmentPresentationUtils.js";
|
|
3
3
|
import { deriveScanNarrative } from "../../deriveScanNarrative.js";
|
|
4
4
|
import { buildProfileFromAssessment } from "../profile/buildProfileFromAssessment.js";
|
|
@@ -23,11 +23,13 @@ export function buildScanPresentationBundle(input) {
|
|
|
23
23
|
const presentation = toPublicPresentation(normalized.presentation);
|
|
24
24
|
const profile = buildProfileFromAssessment(normalized, presentation, input.result);
|
|
25
25
|
const facts = deriveScanNarrative(input.result);
|
|
26
|
+
const authored = extractAuthoredCommunication(normalized);
|
|
26
27
|
return {
|
|
27
28
|
assessment: normalized,
|
|
28
29
|
presentation,
|
|
29
30
|
profile,
|
|
30
31
|
facts,
|
|
31
32
|
result: input.result,
|
|
33
|
+
...authored,
|
|
32
34
|
};
|
|
33
35
|
}
|
|
@@ -1,19 +1,19 @@
|
|
|
1
|
-
import type { Assessment, AssessmentPresentationPublic } from "@mergesignal/contracts";
|
|
1
|
+
import type { Assessment, AssessmentPresentationPublic, AuthoredCommunicationAccessors } from "@mergesignal/contracts";
|
|
2
2
|
import type { ScanNarrativeFacts } from "../../scanNarrativeFacts.js";
|
|
3
3
|
import type { ScanResult } from "../../types.js";
|
|
4
4
|
import type { PresentationProfile } from "../profile/presentationProfile.js";
|
|
5
|
-
export type ScanPresentationBundle = {
|
|
5
|
+
export type ScanPresentationBundle = AuthoredCommunicationAccessors & {
|
|
6
6
|
assessment: Assessment;
|
|
7
7
|
presentation: AssessmentPresentationPublic;
|
|
8
8
|
profile: PresentationProfile;
|
|
9
9
|
/**
|
|
10
10
|
* Evidence layout only — not an authority for posture, concern, or intensity.
|
|
11
|
-
* @deprecated Prefer
|
|
11
|
+
* @deprecated Prefer bundle accessors for authored communication; V3 migration only.
|
|
12
12
|
*/
|
|
13
13
|
facts: ScanNarrativeFacts;
|
|
14
14
|
/**
|
|
15
15
|
* Projection-only reference to the raw scan payload.
|
|
16
|
-
*
|
|
16
|
+
* @deprecated V3 migration only — surfaces must use accessors for decision meaning.
|
|
17
17
|
*/
|
|
18
18
|
result: ScanResult;
|
|
19
19
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scanPresentationBundle.d.ts","sourceRoot":"","sources":["../../../src/presentation/orchestration/scanPresentationBundle.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,UAAU,EACV,4BAA4B,
|
|
1
|
+
{"version":3,"file":"scanPresentationBundle.d.ts","sourceRoot":"","sources":["../../../src/presentation/orchestration/scanPresentationBundle.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,UAAU,EACV,4BAA4B,EAC5B,8BAA8B,EAC/B,MAAM,wBAAwB,CAAC;AAChC,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,6BAA6B,CAAC;AACtE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,mCAAmC,CAAC;AAE7E,MAAM,MAAM,sBAAsB,GAAG,8BAA8B,GAAG;IACpE,UAAU,EAAE,UAAU,CAAC;IACvB,YAAY,EAAE,4BAA4B,CAAC;IAC3C,OAAO,EAAE,mBAAmB,CAAC;IAC7B;;;OAGG;IACH,KAAK,EAAE,kBAAkB,CAAC;IAC1B;;;OAGG;IACH,MAAM,EAAE,UAAU,CAAC;CACpB,CAAC"}
|
|
@@ -245,6 +245,164 @@ export declare const engineOutputScanResultSchema: z.ZodObject<{
|
|
|
245
245
|
}, z.core.$strip>;
|
|
246
246
|
reasoning: z.ZodArray<z.ZodString>;
|
|
247
247
|
confidenceRationale: z.ZodString;
|
|
248
|
+
notAffectedLine: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
249
|
+
resolutionLine: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
250
|
+
outcome: z.ZodOptional<z.ZodEnum<{
|
|
251
|
+
cleared: "cleared";
|
|
252
|
+
proven_broken: "proven_broken";
|
|
253
|
+
bounded_verify: "bounded_verify";
|
|
254
|
+
abstain: "abstain";
|
|
255
|
+
}>>;
|
|
256
|
+
perPackageOutcome: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
257
|
+
packageName: z.ZodString;
|
|
258
|
+
outcome: z.ZodEnum<{
|
|
259
|
+
cleared: "cleared";
|
|
260
|
+
proven_broken: "proven_broken";
|
|
261
|
+
bounded_verify: "bounded_verify";
|
|
262
|
+
abstain: "abstain";
|
|
263
|
+
}>;
|
|
264
|
+
proofArtifactRefs: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
265
|
+
clearanceEnvelopeRef: z.ZodOptional<z.ZodString>;
|
|
266
|
+
boundedVerifyTargetRefs: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
267
|
+
}, z.core.$strip>>>;
|
|
268
|
+
clearanceEnvelopes: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
269
|
+
packageName: z.ZodString;
|
|
270
|
+
clearedDimensions: z.ZodArray<z.ZodObject<{
|
|
271
|
+
kind: z.ZodEnum<{
|
|
272
|
+
type_surface: "type_surface";
|
|
273
|
+
manifest: "manifest";
|
|
274
|
+
exports: "exports";
|
|
275
|
+
entrypoint: "entrypoint";
|
|
276
|
+
peer_dependency: "peer_dependency";
|
|
277
|
+
engine_constraint: "engine_constraint";
|
|
278
|
+
artifact_layout: "artifact_layout";
|
|
279
|
+
documented_breaking: "documented_breaking";
|
|
280
|
+
}>;
|
|
281
|
+
basis: z.ZodEnum<{
|
|
282
|
+
proof_pass: "proof_pass";
|
|
283
|
+
no_impact_proven: "no_impact_proven";
|
|
284
|
+
}>;
|
|
285
|
+
proofArtifactRef: z.ZodOptional<z.ZodString>;
|
|
286
|
+
noImpactProofRef: z.ZodOptional<z.ZodString>;
|
|
287
|
+
}, z.core.$strip>>;
|
|
288
|
+
unclearedDimensions: z.ZodArray<z.ZodObject<{
|
|
289
|
+
kind: z.ZodEnum<{
|
|
290
|
+
type_surface: "type_surface";
|
|
291
|
+
manifest: "manifest";
|
|
292
|
+
exports: "exports";
|
|
293
|
+
entrypoint: "entrypoint";
|
|
294
|
+
peer_dependency: "peer_dependency";
|
|
295
|
+
engine_constraint: "engine_constraint";
|
|
296
|
+
artifact_layout: "artifact_layout";
|
|
297
|
+
documented_breaking: "documented_breaking";
|
|
298
|
+
}>;
|
|
299
|
+
reason: z.ZodEnum<{
|
|
300
|
+
proof_failed: "proof_failed";
|
|
301
|
+
proof_inconclusive: "proof_inconclusive";
|
|
302
|
+
no_producer_available: "no_producer_available";
|
|
303
|
+
representative_precision_only: "representative_precision_only";
|
|
304
|
+
architectural_precision_only: "architectural_precision_only";
|
|
305
|
+
opaque_delta: "opaque_delta";
|
|
306
|
+
hypothesized_breaking: "hypothesized_breaking";
|
|
307
|
+
}>;
|
|
308
|
+
boundedVerifyTarget: z.ZodOptional<z.ZodObject<{
|
|
309
|
+
targetId: z.ZodString;
|
|
310
|
+
packageName: z.ZodString;
|
|
311
|
+
kind: z.ZodEnum<{
|
|
312
|
+
file_location: "file_location";
|
|
313
|
+
config_path: "config_path";
|
|
314
|
+
behavioral_scenario: "behavioral_scenario";
|
|
315
|
+
}>;
|
|
316
|
+
file: z.ZodOptional<z.ZodString>;
|
|
317
|
+
line: z.ZodOptional<z.ZodNumber>;
|
|
318
|
+
configKey: z.ZodOptional<z.ZodString>;
|
|
319
|
+
scenario: z.ZodOptional<z.ZodString>;
|
|
320
|
+
whatToVerify: z.ZodString;
|
|
321
|
+
whyAutomationStopped: z.ZodString;
|
|
322
|
+
whatProofWouldResolveIt: z.ZodString;
|
|
323
|
+
}, z.core.$strip>>;
|
|
324
|
+
}, z.core.$strip>>;
|
|
325
|
+
coverageClass: z.ZodEnum<{
|
|
326
|
+
none: "none";
|
|
327
|
+
full: "full";
|
|
328
|
+
representative: "representative";
|
|
329
|
+
}>;
|
|
330
|
+
}, z.core.$strip>>>;
|
|
331
|
+
boundedVerifyTargets: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
332
|
+
targetId: z.ZodString;
|
|
333
|
+
packageName: z.ZodString;
|
|
334
|
+
kind: z.ZodEnum<{
|
|
335
|
+
file_location: "file_location";
|
|
336
|
+
config_path: "config_path";
|
|
337
|
+
behavioral_scenario: "behavioral_scenario";
|
|
338
|
+
}>;
|
|
339
|
+
file: z.ZodOptional<z.ZodString>;
|
|
340
|
+
line: z.ZodOptional<z.ZodNumber>;
|
|
341
|
+
configKey: z.ZodOptional<z.ZodString>;
|
|
342
|
+
scenario: z.ZodOptional<z.ZodString>;
|
|
343
|
+
whatToVerify: z.ZodString;
|
|
344
|
+
whyAutomationStopped: z.ZodString;
|
|
345
|
+
whatProofWouldResolveIt: z.ZodString;
|
|
346
|
+
}, z.core.$strip>>>;
|
|
347
|
+
evidenceSufficiencyVerdict: z.ZodOptional<z.ZodObject<{
|
|
348
|
+
sufficient: z.ZodBoolean;
|
|
349
|
+
clearanceEligible: z.ZodBoolean;
|
|
350
|
+
provenBrokenEligible: z.ZodBoolean;
|
|
351
|
+
boundedVerifyEligible: z.ZodBoolean;
|
|
352
|
+
blockers: z.ZodArray<z.ZodObject<{
|
|
353
|
+
kind: z.ZodEnum<{
|
|
354
|
+
private_package: "private_package";
|
|
355
|
+
opaque_mutation: "opaque_mutation";
|
|
356
|
+
unsupported_ecosystem: "unsupported_ecosystem";
|
|
357
|
+
partial_monorepo_scan: "partial_monorepo_scan";
|
|
358
|
+
repository_coverage_insufficient: "repository_coverage_insufficient";
|
|
359
|
+
package_facts_missing: "package_facts_missing";
|
|
360
|
+
correlation_abstained: "correlation_abstained";
|
|
361
|
+
proof_coverage_insufficient: "proof_coverage_insufficient";
|
|
362
|
+
proof_execution_failed: "proof_execution_failed";
|
|
363
|
+
hypothesized_breaking_unresolved: "hypothesized_breaking_unresolved";
|
|
364
|
+
advisory_blocking: "advisory_blocking";
|
|
365
|
+
conflicting_proof_results: "conflicting_proof_results";
|
|
366
|
+
}>;
|
|
367
|
+
packageName: z.ZodOptional<z.ZodString>;
|
|
368
|
+
detail: z.ZodOptional<z.ZodString>;
|
|
369
|
+
}, z.core.$strip>>;
|
|
370
|
+
perPackage: z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
371
|
+
packageName: z.ZodString;
|
|
372
|
+
clearanceEligible: z.ZodBoolean;
|
|
373
|
+
provenBrokenEligible: z.ZodBoolean;
|
|
374
|
+
blockers: z.ZodArray<z.ZodObject<{
|
|
375
|
+
kind: z.ZodEnum<{
|
|
376
|
+
private_package: "private_package";
|
|
377
|
+
opaque_mutation: "opaque_mutation";
|
|
378
|
+
unsupported_ecosystem: "unsupported_ecosystem";
|
|
379
|
+
partial_monorepo_scan: "partial_monorepo_scan";
|
|
380
|
+
repository_coverage_insufficient: "repository_coverage_insufficient";
|
|
381
|
+
package_facts_missing: "package_facts_missing";
|
|
382
|
+
correlation_abstained: "correlation_abstained";
|
|
383
|
+
proof_coverage_insufficient: "proof_coverage_insufficient";
|
|
384
|
+
proof_execution_failed: "proof_execution_failed";
|
|
385
|
+
hypothesized_breaking_unresolved: "hypothesized_breaking_unresolved";
|
|
386
|
+
advisory_blocking: "advisory_blocking";
|
|
387
|
+
conflicting_proof_results: "conflicting_proof_results";
|
|
388
|
+
}>;
|
|
389
|
+
packageName: z.ZodOptional<z.ZodString>;
|
|
390
|
+
detail: z.ZodOptional<z.ZodString>;
|
|
391
|
+
}, z.core.$strip>>;
|
|
392
|
+
}, z.core.$strip>>;
|
|
393
|
+
}, z.core.$strip>>;
|
|
394
|
+
abstainReasons: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
395
|
+
kind: z.ZodEnum<{
|
|
396
|
+
private_package: "private_package";
|
|
397
|
+
opaque_mutation: "opaque_mutation";
|
|
398
|
+
unsupported_ecosystem: "unsupported_ecosystem";
|
|
399
|
+
partial_monorepo_scan: "partial_monorepo_scan";
|
|
400
|
+
no_honest_bounded_target: "no_honest_bounded_target";
|
|
401
|
+
insufficient_collection: "insufficient_collection";
|
|
402
|
+
}>;
|
|
403
|
+
packageName: z.ZodOptional<z.ZodString>;
|
|
404
|
+
detail: z.ZodOptional<z.ZodString>;
|
|
405
|
+
}, z.core.$strip>>>;
|
|
248
406
|
}, z.core.$strip>;
|
|
249
407
|
prRisk: z.ZodObject<{
|
|
250
408
|
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"}
|