@mergesignal/shared 0.9.1 → 0.11.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.
Files changed (34) hide show
  1. package/dist/assessmentProjection.d.ts +10 -1
  2. package/dist/assessmentProjection.d.ts.map +1 -1
  3. package/dist/assessmentProjection.js +38 -7
  4. package/dist/assessmentProjection.verificationChannel.test.d.ts +2 -0
  5. package/dist/assessmentProjection.verificationChannel.test.d.ts.map +1 -0
  6. package/dist/assessmentProjection.verificationChannel.test.js +110 -0
  7. package/dist/fixtures/assessmentFixtures.d.ts +1 -1
  8. package/dist/fixtures/assessmentFixtures.d.ts.map +1 -1
  9. package/dist/fixtures/assessmentFixtures.js +10 -10
  10. package/dist/fixtures/assessmentScopeFixtures.d.ts +4 -2
  11. package/dist/fixtures/assessmentScopeFixtures.d.ts.map +1 -1
  12. package/dist/fixtures/assessmentScopeFixtures.js +13 -3
  13. package/dist/index.d.ts +1 -1
  14. package/dist/index.d.ts.map +1 -1
  15. package/dist/index.js +1 -1
  16. package/dist/presentation/dto/assessmentPresentationFields.d.ts +2 -0
  17. package/dist/presentation/dto/assessmentPresentationFields.d.ts.map +1 -1
  18. package/dist/presentation/presentation.test.js +3 -1
  19. package/dist/presentation/presentationPersonas.test.js +2 -0
  20. package/dist/presentation/profile/buildProfileFromAssessment.d.ts.map +1 -1
  21. package/dist/presentation/profile/buildProfileFromAssessment.js +2 -2
  22. package/dist/presentation/projectAssessmentFields.d.ts.map +1 -1
  23. package/dist/presentation/projectAssessmentFields.js +4 -2
  24. package/dist/presentation/surfaceParity.test.js +6 -0
  25. package/dist/presentation/verificationChannelParity.test.d.ts +2 -0
  26. package/dist/presentation/verificationChannelParity.test.d.ts.map +1 -0
  27. package/dist/presentation/verificationChannelParity.test.js +57 -0
  28. package/dist/repoIntelligenceSchema.contract.test.js +32 -0
  29. package/dist/repoIntelligenceSchema.d.ts +22 -4
  30. package/dist/repoIntelligenceSchema.d.ts.map +1 -1
  31. package/dist/repoIntelligenceSchema.js +22 -1
  32. package/dist/scanResultSchema.d.ts +6 -0
  33. package/dist/scanResultSchema.d.ts.map +1 -1
  34. package/package.json +2 -2
@@ -1,7 +1,16 @@
1
1
  import type { ScanResult } from "./types.js";
2
2
  import { type RepoIntelligence } from "./repoIntelligenceSchema.js";
3
- import type { Assessment, AssessmentPresentationPublic, ReachVisibility } from "@mergesignal/contracts";
3
+ import type { Assessment, AssessmentPresentationPublic, ReachVisibility, VerificationIntensity } from "@mergesignal/contracts";
4
4
  import type { PresentationStatus } from "./presentation/dto/types.js";
5
+ export type VerificationChannel = "runtime" | "artifact" | "none";
6
+ export declare function resolveVerificationChannel(intensity: VerificationIntensity): VerificationChannel;
7
+ export declare function collectRuntimeVerificationFocus(result: ScanResult): string[];
8
+ export declare function collectArtifactVerificationFocus(result: ScanResult): string[];
9
+ export declare function collectVerificationFocusForPresentation(presentation: AssessmentPresentationPublic, result: ScanResult): {
10
+ channel: VerificationChannel;
11
+ focus: string[];
12
+ };
13
+ /** @deprecated Use collectVerificationFocusForPresentation or channel-specific collectors. */
5
14
  export declare function collectVerificationFocus(result: ScanResult): string[];
6
15
  export declare function reachVisibilityLabel(visibility: ReachVisibility): string | undefined;
7
16
  export declare function formatAssessmentHeadline(assessment: Assessment, status: PresentationStatus): string;
@@ -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,EAChB,MAAM,wBAAwB,CAAC;AAOhC,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,6BAA6B,CAAC;AAgCtE,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,EAAE,CAkBrE;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,CAIlE;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,CAIV;AAED,wBAAgB,qBAAqB,CAAC,EAAE,EAAE,gBAAgB,GAAG,IAAI,GAAG,MAAM,EAAE,CAI3E"}
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,CAIlE;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,CAOV;AAED,wBAAgB,qBAAqB,CAAC,EAAE,EAAE,gBAAgB,GAAG,IAAI,GAAG,MAAM,EAAE,CAI3E"}
@@ -32,12 +32,7 @@ function surfaceHintFromAssessment(assessment) {
32
32
  }
33
33
  return "application code";
34
34
  }
35
- export function collectVerificationFocus(result) {
36
- const scope = result.assessment?.verificationScope;
37
- if (scope?.focus?.length)
38
- return [...scope.focus];
39
- const packages = scope?.packages ?? [];
40
- const parsed = safeParseRepoIntelligence(result.repoIntelligence);
35
+ function collectVerificationFocusFromPackages(packages, parsed) {
41
36
  if (!parsed.ok)
42
37
  return [];
43
38
  const labels = [];
@@ -54,6 +49,42 @@ export function collectVerificationFocus(result) {
54
49
  }
55
50
  return labels;
56
51
  }
52
+ export function resolveVerificationChannel(intensity) {
53
+ if (intensity === "none")
54
+ return "none";
55
+ if (intensity === "required")
56
+ return "runtime";
57
+ return "artifact";
58
+ }
59
+ export function collectRuntimeVerificationFocus(result) {
60
+ const scope = result.assessment?.verificationScope;
61
+ if (scope?.focus?.length)
62
+ return [...scope.focus];
63
+ const packages = scope?.packages ?? [];
64
+ return collectVerificationFocusFromPackages(packages, safeParseRepoIntelligence(result.repoIntelligence));
65
+ }
66
+ export function collectArtifactVerificationFocus(result) {
67
+ const artifactGrounded = result.assessment?.verificationScope?.artifactGrounded;
68
+ if (!artifactGrounded)
69
+ return [];
70
+ if (artifactGrounded.focus.length > 0)
71
+ return [...artifactGrounded.focus];
72
+ return collectVerificationFocusFromPackages(artifactGrounded.packages, safeParseRepoIntelligence(result.repoIntelligence));
73
+ }
74
+ export function collectVerificationFocusForPresentation(presentation, result) {
75
+ const channel = resolveVerificationChannel(presentation.verificationIntensity);
76
+ if (channel === "none") {
77
+ return { channel, focus: [] };
78
+ }
79
+ if (channel === "runtime") {
80
+ return { channel, focus: collectRuntimeVerificationFocus(result) };
81
+ }
82
+ return { channel, focus: collectArtifactVerificationFocus(result) };
83
+ }
84
+ /** @deprecated Use collectVerificationFocusForPresentation or channel-specific collectors. */
85
+ export function collectVerificationFocus(result) {
86
+ return collectRuntimeVerificationFocus(result);
87
+ }
57
88
  export function reachVisibilityLabel(visibility) {
58
89
  switch (visibility) {
59
90
  case "hidden":
@@ -118,7 +149,7 @@ export function projectInsightLines(assessment, result) {
118
149
  export function projectVerificationActions(assessment, presentation, result, max) {
119
150
  if (presentation.verificationIntensity === "none")
120
151
  return [];
121
- const focus = collectVerificationFocus(result);
152
+ const { focus } = collectVerificationFocusForPresentation(presentation, result);
122
153
  return focus.slice(0, max);
123
154
  }
124
155
  export function applicationAreaLabels(ri) {
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=assessmentProjection.verificationChannel.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"assessmentProjection.verificationChannel.test.d.ts","sourceRoot":"","sources":["../src/assessmentProjection.verificationChannel.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,110 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { artifactGroundedScopeFor, minimalReviewFocalPoint, verificationScopeFor, withAssessmentScope, } from "./fixtures/assessmentScopeFixtures.js";
3
+ import { assessmentFastifyRuntime, assessmentPrettier, assessmentTypescriptPatch, } from "./fixtures/assessmentFixtures.js";
4
+ import { collectArtifactVerificationFocus, collectRuntimeVerificationFocus, collectVerificationFocusForPresentation, resolveVerificationChannel, } from "./assessmentProjection.js";
5
+ import { toPublicPresentation } from "./assessmentPresentationUtils.js";
6
+ function scanResultWithAssessment(assessment) {
7
+ return {
8
+ totalScore: 30,
9
+ layerScores: {
10
+ security: 10,
11
+ maintainability: 10,
12
+ ecosystem: 10,
13
+ upgradeImpact: 0,
14
+ },
15
+ findings: [],
16
+ generatedAt: "2026-01-01T00:00:00.000Z",
17
+ assessment,
18
+ decision: {
19
+ recommendation: "safe",
20
+ confidence: "high",
21
+ reasoning: ["fixture"],
22
+ },
23
+ repoIntelligence: {},
24
+ changedPackages: assessment.reviewFocalPoint.anchors,
25
+ };
26
+ }
27
+ describe("resolveVerificationChannel", () => {
28
+ it("maps intensity to presentation channel", () => {
29
+ expect(resolveVerificationChannel("none")).toBe("none");
30
+ expect(resolveVerificationChannel("advisory")).toBe("artifact");
31
+ expect(resolveVerificationChannel("required")).toBe("runtime");
32
+ });
33
+ });
34
+ describe("collectVerificationFocusForPresentation", () => {
35
+ it("fastify required: runtime focus only", () => {
36
+ const result = scanResultWithAssessment(assessmentFastifyRuntime);
37
+ const presentation = toPublicPresentation(assessmentFastifyRuntime.presentation);
38
+ const projected = collectVerificationFocusForPresentation(presentation, result);
39
+ expect(projected.channel).toBe("runtime");
40
+ expect(projected.focus).toEqual(["routes", "middleware"]);
41
+ expect(collectRuntimeVerificationFocus(result)).toEqual(projected.focus);
42
+ expect(collectArtifactVerificationFocus(result)).toEqual([]);
43
+ });
44
+ it("typescript advisory: artifact focus only", () => {
45
+ const result = scanResultWithAssessment(assessmentTypescriptPatch);
46
+ const presentation = toPublicPresentation(assessmentTypescriptPatch.presentation);
47
+ const projected = collectVerificationFocusForPresentation(presentation, result);
48
+ expect(projected.channel).toBe("artifact");
49
+ expect(projected.focus).toEqual(["typecheck"]);
50
+ expect(collectArtifactVerificationFocus(result)).toEqual(["typecheck"]);
51
+ expect(collectRuntimeVerificationFocus(result)).toEqual([]);
52
+ });
53
+ it("prettier advisory: artifact focus only", () => {
54
+ const result = scanResultWithAssessment(assessmentPrettier);
55
+ const presentation = toPublicPresentation(assessmentPrettier.presentation);
56
+ const projected = collectVerificationFocusForPresentation(presentation, result);
57
+ expect(projected.channel).toBe("artifact");
58
+ expect(projected.focus).toEqual(["format"]);
59
+ });
60
+ it("none intensity: empty focus", () => {
61
+ const assessment = withAssessmentScope({
62
+ ...assessmentTypescriptPatch,
63
+ presentation: {
64
+ ...assessmentTypescriptPatch.presentation,
65
+ verificationIntensity: "none",
66
+ },
67
+ }, {
68
+ reviewFocalPoint: minimalReviewFocalPoint(["typescript"]),
69
+ verificationScope: verificationScopeFor(["fastify"], ["routes"], artifactGroundedScopeFor(["typescript"], ["typecheck"])),
70
+ });
71
+ const result = scanResultWithAssessment(assessment);
72
+ const projected = collectVerificationFocusForPresentation(toPublicPresentation(assessment.presentation), result);
73
+ expect(projected.channel).toBe("none");
74
+ expect(projected.focus).toEqual([]);
75
+ });
76
+ it("conflict fixture: advisory uses artifact only", () => {
77
+ const assessment = withAssessmentScope({
78
+ ...assessmentTypescriptPatch,
79
+ presentation: {
80
+ ...assessmentTypescriptPatch.presentation,
81
+ verificationIntensity: "advisory",
82
+ },
83
+ }, {
84
+ reviewFocalPoint: minimalReviewFocalPoint(["typescript"]),
85
+ verificationScope: verificationScopeFor(["fastify"], ["routes"], artifactGroundedScopeFor(["typescript"], ["typecheck"])),
86
+ });
87
+ const result = scanResultWithAssessment(assessment);
88
+ const projected = collectVerificationFocusForPresentation(toPublicPresentation(assessment.presentation), result);
89
+ expect(projected.channel).toBe("artifact");
90
+ expect(projected.focus).toEqual(["typecheck"]);
91
+ expect(projected.focus).not.toContain("routes");
92
+ });
93
+ it("conflict fixture: required uses runtime only", () => {
94
+ const assessment = withAssessmentScope({
95
+ ...assessmentFastifyRuntime,
96
+ presentation: {
97
+ ...assessmentFastifyRuntime.presentation,
98
+ verificationIntensity: "required",
99
+ },
100
+ }, {
101
+ reviewFocalPoint: minimalReviewFocalPoint(["fastify"]),
102
+ verificationScope: verificationScopeFor(["fastify"], ["routes", "middleware"], artifactGroundedScopeFor(["typescript"], ["typecheck"])),
103
+ });
104
+ const result = scanResultWithAssessment(assessment);
105
+ const projected = collectVerificationFocusForPresentation(toPublicPresentation(assessment.presentation), result);
106
+ expect(projected.channel).toBe("runtime");
107
+ expect(projected.focus).toEqual(["routes", "middleware"]);
108
+ expect(projected.focus).not.toContain("typecheck");
109
+ });
110
+ });
@@ -1,7 +1,7 @@
1
1
  import type { Assessment } from "@mergesignal/contracts";
2
2
  export declare const assessmentTypescriptPatch: Assessment;
3
- export declare const assessmentPrettier: Assessment;
4
3
  export declare const assessmentEslint: Assessment;
4
+ export declare const assessmentPrettier: Assessment;
5
5
  export declare const assessmentVitest: Assessment;
6
6
  export declare const assessmentFastifyRuntime: Assessment;
7
7
  export declare const assessmentBullmq: Assessment;
@@ -1 +1 @@
1
- {"version":3,"file":"assessmentFixtures.d.ts","sourceRoot":"","sources":["../../src/fixtures/assessmentFixtures.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AA0BzD,eAAO,MAAM,yBAAyB,EAAE,UAevC,CAAC;AAEF,eAAO,MAAM,kBAAkB,EAAE,UAUhC,CAAC;AAEF,eAAO,MAAM,gBAAgB,EAAE,UAS9B,CAAC;AAEF,eAAO,MAAM,gBAAgB,EAAE,UAe9B,CAAC;AAEF,eAAO,MAAM,wBAAwB,EAAE,UAyBtC,CAAC;AAEF,eAAO,MAAM,gBAAgB,EAAE,UA6B9B,CAAC;AAEF,eAAO,MAAM,kBAAkB,EAAE,UAyBhC,CAAC;AAEF,0EAA0E;AAC1E,eAAO,MAAM,gCAAgC,EAAE,UAgC9C,CAAC;AAEF,eAAO,MAAM,wBAAwB,EAAE,UA2BtC,CAAC;AAEF,eAAO,MAAM,cAAc,EAAE,UA6B5B,CAAC;AAEF,eAAO,MAAM,qBAAqB,EAAE,UAqBnC,CAAC"}
1
+ {"version":3,"file":"assessmentFixtures.d.ts","sourceRoot":"","sources":["../../src/fixtures/assessmentFixtures.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AA2BzD,eAAO,MAAM,yBAAyB,EAAE,UAmBvC,CAAC;AAEF,eAAO,MAAM,gBAAgB,EAAE,UAa9B,CAAC;AAEF,eAAO,MAAM,kBAAkB,EAAE,UAchC,CAAC;AAEF,eAAO,MAAM,gBAAgB,EAAE,UAuB9B,CAAC;AAEF,eAAO,MAAM,wBAAwB,EAAE,UAyBtC,CAAC;AAEF,eAAO,MAAM,gBAAgB,EAAE,UA6B9B,CAAC;AAEF,eAAO,MAAM,kBAAkB,EAAE,UAyBhC,CAAC;AAEF,0EAA0E;AAC1E,eAAO,MAAM,gCAAgC,EAAE,UAgC9C,CAAC;AAEF,eAAO,MAAM,wBAAwB,EAAE,UA2BtC,CAAC;AAEF,eAAO,MAAM,cAAc,EAAE,UA6B5B,CAAC;AAEF,eAAO,MAAM,qBAAqB,EAAE,UAqBnC,CAAC"}
@@ -1,4 +1,4 @@
1
- import { emptyReachScope, emptyVerificationScope, minimalReviewFocalPoint, reachScopeFor, verificationScopeFor, withAssessmentScope, } from "./assessmentScopeFixtures.js";
1
+ import { artifactGroundedScopeFor, emptyReachScope, emptyVerificationScope, minimalReviewFocalPoint, reachScopeFor, verificationScopeFor, withAssessmentScope, } from "./assessmentScopeFixtures.js";
2
2
  const safeToolingPresentation = {
3
3
  narrativeIntensity: "minimal",
4
4
  reachVisibility: "hidden",
@@ -24,22 +24,22 @@ export const assessmentTypescriptPatch = withAssessmentScope({
24
24
  }, {
25
25
  reviewFocalPoint: minimalReviewFocalPoint(["typescript"]),
26
26
  reachScope: emptyReachScope(),
27
- verificationScope: emptyVerificationScope(),
27
+ verificationScope: verificationScopeFor([], [], artifactGroundedScopeFor(["typescript"], ["typecheck"], ["package.json"])),
28
28
  });
29
- export const assessmentPrettier = withAssessmentScope({
29
+ export const assessmentEslint = withAssessmentScope({
30
30
  ...assessmentTypescriptPatch,
31
- factors: ["tooling_maintenance"],
32
31
  }, {
33
- reviewFocalPoint: minimalReviewFocalPoint(["prettier"]),
32
+ reviewFocalPoint: minimalReviewFocalPoint(["eslint"]),
34
33
  reachScope: emptyReachScope(),
35
- verificationScope: emptyVerificationScope(),
34
+ verificationScope: verificationScopeFor([], [], artifactGroundedScopeFor(["eslint"], ["lint"], [".eslintrc.cjs"])),
36
35
  });
37
- export const assessmentEslint = withAssessmentScope({
36
+ export const assessmentPrettier = withAssessmentScope({
38
37
  ...assessmentTypescriptPatch,
38
+ factors: ["tooling_maintenance"],
39
39
  }, {
40
- reviewFocalPoint: minimalReviewFocalPoint(["eslint"]),
40
+ reviewFocalPoint: minimalReviewFocalPoint(["prettier"]),
41
41
  reachScope: emptyReachScope(),
42
- verificationScope: emptyVerificationScope(),
42
+ verificationScope: verificationScopeFor([], [], artifactGroundedScopeFor(["prettier"], ["format"], [".prettierrc"])),
43
43
  });
44
44
  export const assessmentVitest = withAssessmentScope({
45
45
  posture: "safe",
@@ -52,7 +52,7 @@ export const assessmentVitest = withAssessmentScope({
52
52
  }, {
53
53
  reviewFocalPoint: minimalReviewFocalPoint(["vitest"]),
54
54
  reachScope: emptyReachScope(),
55
- verificationScope: emptyVerificationScope(),
55
+ verificationScope: verificationScopeFor([], [], artifactGroundedScopeFor(["vitest"], ["test_suite"], ["vitest.config.ts"])),
56
56
  });
57
57
  export const assessmentFastifyRuntime = withAssessmentScope({
58
58
  posture: "needs_review",
@@ -1,4 +1,4 @@
1
- import type { Assessment, FocalElectionDimension, ReachScope, ReviewEpisodeShape, ReviewFocalPoint, VerificationScope } from "@mergesignal/contracts";
1
+ import type { ArtifactGroundedVerificationScope, Assessment, FocalElectionDimension, ReachScope, ReviewEpisodeShape, ReviewFocalPoint, VerificationScope } from "@mergesignal/contracts";
2
2
  export declare function minimalReviewFocalPoint(anchors: string[], opts?: {
3
3
  episodeShape?: ReviewEpisodeShape;
4
4
  supportingPackages?: string[];
@@ -6,8 +6,10 @@ export declare function minimalReviewFocalPoint(anchors: string[], opts?: {
6
6
  }): ReviewFocalPoint;
7
7
  export declare function emptyReachScope(): ReachScope;
8
8
  export declare function reachScopeFor(packages: string[], maxBucket?: ReachScope["maxBucket"]): ReachScope;
9
+ export declare function emptyArtifactGrounded(): ArtifactGroundedVerificationScope;
10
+ export declare function artifactGroundedScopeFor(packages: string[], focus?: string[], artifactPaths?: string[]): ArtifactGroundedVerificationScope;
9
11
  export declare function emptyVerificationScope(): VerificationScope;
10
- export declare function verificationScopeFor(packages: string[], focus?: string[]): VerificationScope;
12
+ export declare function verificationScopeFor(packages: string[], focus?: string[], artifactGrounded?: ArtifactGroundedVerificationScope): VerificationScope;
11
13
  /** Attach focal/scope fields required by assessmentSchema ABI 2. */
12
14
  export declare function withAssessmentScope(assessment: Omit<Assessment, "reviewFocalPoint" | "reachScope" | "verificationScope">, scope: {
13
15
  reviewFocalPoint: ReviewFocalPoint;
@@ -1 +1 @@
1
- {"version":3,"file":"assessmentScopeFixtures.d.ts","sourceRoot":"","sources":["../../src/fixtures/assessmentScopeFixtures.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,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,sBAAsB,IAAI,iBAAiB,CAE1D;AAED,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,MAAM,EAAE,EAClB,KAAK,GAAE,MAAM,EAAO,GACnB,iBAAiB,CAEnB;AAED,oEAAoE;AACpE,wBAAgB,mBAAmB,CACjC,UAAU,EAAE,IAAI,CACd,UAAU,EACV,kBAAkB,GAAG,YAAY,GAAG,mBAAmB,CACxD,EACD,KAAK,EAAE;IACL,gBAAgB,EAAE,gBAAgB,CAAC;IACnC,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB,iBAAiB,CAAC,EAAE,iBAAiB,CAAC;CACvC,GACA,UAAU,CAOZ"}
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,EACV,kBAAkB,GAAG,YAAY,GAAG,mBAAmB,CACxD,EACD,KAAK,EAAE;IACL,gBAAgB,EAAE,gBAAgB,CAAC;IACnC,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB,iBAAiB,CAAC,EAAE,iBAAiB,CAAC;CACvC,GACA,UAAU,CAOZ"}
@@ -25,11 +25,21 @@ export function emptyReachScope() {
25
25
  export function reachScopeFor(packages, maxBucket = "moderate") {
26
26
  return { packages, maxBucket };
27
27
  }
28
+ export function emptyArtifactGrounded() {
29
+ return { packages: [], focus: [], artifactPaths: [] };
30
+ }
31
+ export function artifactGroundedScopeFor(packages, focus = [], artifactPaths = []) {
32
+ return { packages, focus, artifactPaths };
33
+ }
28
34
  export function emptyVerificationScope() {
29
- return { packages: [], focus: [] };
35
+ return {
36
+ packages: [],
37
+ focus: [],
38
+ artifactGrounded: emptyArtifactGrounded(),
39
+ };
30
40
  }
31
- export function verificationScopeFor(packages, focus = []) {
32
- return { packages, focus };
41
+ export function verificationScopeFor(packages, focus = [], artifactGrounded = emptyArtifactGrounded()) {
42
+ return { packages, focus, artifactGrounded };
33
43
  }
34
44
  /** Attach focal/scope fields required by assessmentSchema ABI 2. */
35
45
  export function withAssessmentScope(assessment, scope) {
package/dist/index.d.ts CHANGED
@@ -29,6 +29,6 @@ export * from "./trustedScanGuards.js";
29
29
  export * from "./actionsStepSummary.js";
30
30
  export * from "./productMessaging.js";
31
31
  export * from "./presentation/index.js";
32
- export { emptyReachScope, emptyVerificationScope, minimalReviewFocalPoint, reachScopeFor, verificationScopeFor, withAssessmentScope, } from "./fixtures/assessmentScopeFixtures.js";
32
+ export { emptyReachScope, emptyVerificationScope, emptyArtifactGrounded, artifactGroundedScopeFor, minimalReviewFocalPoint, reachScopeFor, verificationScopeFor, withAssessmentScope, } from "./fixtures/assessmentScopeFixtures.js";
33
33
  export { assessmentStub, assessmentTypescriptPatch, } from "./fixtures/assessmentFixtures.js";
34
34
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,uBAAuB,CAAC;AACtC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,oBAAoB,CAAC;AACnC,cAAc,qBAAqB,CAAC;AACpC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,sBAAsB,CAAC;AACrC,cAAc,0BAA0B,CAAC;AACzC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,iBAAiB,CAAC;AAChC,cAAc,iBAAiB,CAAC;AAChC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,yBAAyB,CAAC;AACxC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,8BAA8B,CAAC;AAC7C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,iCAAiC,CAAC;AAChD,cAAc,0BAA0B,CAAC;AACzC,cAAc,oCAAoC,CAAC;AACnD,cAAc,4BAA4B,CAAC;AAC3C,cAAc,6BAA6B,CAAC;AAC5C,OAAO,EAAE,wCAAwC,EAAE,MAAM,6BAA6B,CAAC;AACvF,cAAc,+BAA+B,CAAC;AAC9C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,uBAAuB,CAAC;AACtC,cAAc,sBAAsB,CAAC;AACrC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,wBAAwB,CAAC;AACvC,cAAc,yBAAyB,CAAC;AACxC,cAAc,uBAAuB,CAAC;AACtC,cAAc,yBAAyB,CAAC;AACxC,OAAO,EACL,eAAe,EACf,sBAAsB,EACtB,uBAAuB,EACvB,aAAa,EACb,oBAAoB,EACpB,mBAAmB,GACpB,MAAM,uCAAuC,CAAC;AAC/C,OAAO,EACL,cAAc,EACd,yBAAyB,GAC1B,MAAM,kCAAkC,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,uBAAuB,CAAC;AACtC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,oBAAoB,CAAC;AACnC,cAAc,qBAAqB,CAAC;AACpC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,sBAAsB,CAAC;AACrC,cAAc,0BAA0B,CAAC;AACzC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,iBAAiB,CAAC;AAChC,cAAc,iBAAiB,CAAC;AAChC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,yBAAyB,CAAC;AACxC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,8BAA8B,CAAC;AAC7C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,iCAAiC,CAAC;AAChD,cAAc,0BAA0B,CAAC;AACzC,cAAc,oCAAoC,CAAC;AACnD,cAAc,4BAA4B,CAAC;AAC3C,cAAc,6BAA6B,CAAC;AAC5C,OAAO,EAAE,wCAAwC,EAAE,MAAM,6BAA6B,CAAC;AACvF,cAAc,+BAA+B,CAAC;AAC9C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,uBAAuB,CAAC;AACtC,cAAc,sBAAsB,CAAC;AACrC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,wBAAwB,CAAC;AACvC,cAAc,yBAAyB,CAAC;AACxC,cAAc,uBAAuB,CAAC;AACtC,cAAc,yBAAyB,CAAC;AACxC,OAAO,EACL,eAAe,EACf,sBAAsB,EACtB,qBAAqB,EACrB,wBAAwB,EACxB,uBAAuB,EACvB,aAAa,EACb,oBAAoB,EACpB,mBAAmB,GACpB,MAAM,uCAAuC,CAAC;AAC/C,OAAO,EACL,cAAc,EACd,yBAAyB,GAC1B,MAAM,kCAAkC,CAAC"}
package/dist/index.js CHANGED
@@ -29,5 +29,5 @@ export * from "./trustedScanGuards.js";
29
29
  export * from "./actionsStepSummary.js";
30
30
  export * from "./productMessaging.js";
31
31
  export * from "./presentation/index.js";
32
- export { emptyReachScope, emptyVerificationScope, minimalReviewFocalPoint, reachScopeFor, verificationScopeFor, withAssessmentScope, } from "./fixtures/assessmentScopeFixtures.js";
32
+ export { emptyReachScope, emptyVerificationScope, emptyArtifactGrounded, artifactGroundedScopeFor, minimalReviewFocalPoint, reachScopeFor, verificationScopeFor, withAssessmentScope, } from "./fixtures/assessmentScopeFixtures.js";
33
33
  export { assessmentStub, assessmentTypescriptPatch, } from "./fixtures/assessmentFixtures.js";
@@ -1,4 +1,5 @@
1
1
  import type { MergeConcernKind, NarrativeIntensity, ReachVisibility } from "@mergesignal/contracts";
2
+ import type { VerificationChannel } from "../../assessmentProjection.js";
2
3
  /** Assessment-aligned fields projected identically across surfaces. */
3
4
  export type AssessmentPresentationFields = {
4
5
  posture: "safe" | "needs_review" | "risky";
@@ -6,6 +7,7 @@ export type AssessmentPresentationFields = {
6
7
  factors: string[];
7
8
  reasoning: string[];
8
9
  verificationFocus: string[];
10
+ verificationChannel: VerificationChannel;
9
11
  reachVisibility: ReachVisibility;
10
12
  narrativeIntensity: NarrativeIntensity;
11
13
  };
@@ -1 +1 @@
1
- {"version":3,"file":"assessmentPresentationFields.d.ts","sourceRoot":"","sources":["../../../src/presentation/dto/assessmentPresentationFields.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,gBAAgB,EAChB,kBAAkB,EAClB,eAAe,EAEhB,MAAM,wBAAwB,CAAC;AAEhC,uEAAuE;AACvE,MAAM,MAAM,4BAA4B,GAAG;IACzC,OAAO,EAAE,MAAM,GAAG,cAAc,GAAG,OAAO,CAAC;IAC3C,cAAc,EAAE,gBAAgB,GAAG,IAAI,CAAC;IACxC,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,iBAAiB,EAAE,MAAM,EAAE,CAAC;IAC5B,eAAe,EAAE,eAAe,CAAC;IACjC,kBAAkB,EAAE,kBAAkB,CAAC;CACxC,CAAC"}
1
+ {"version":3,"file":"assessmentPresentationFields.d.ts","sourceRoot":"","sources":["../../../src/presentation/dto/assessmentPresentationFields.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,gBAAgB,EAChB,kBAAkB,EAClB,eAAe,EAEhB,MAAM,wBAAwB,CAAC;AAChC,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,+BAA+B,CAAC;AAEzE,uEAAuE;AACvE,MAAM,MAAM,4BAA4B,GAAG;IACzC,OAAO,EAAE,MAAM,GAAG,cAAc,GAAG,OAAO,CAAC;IAC3C,cAAc,EAAE,gBAAgB,GAAG,IAAI,CAAC;IACxC,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,iBAAiB,EAAE,MAAM,EAAE,CAAC;IAC5B,mBAAmB,EAAE,mBAAmB,CAAC;IACzC,eAAe,EAAE,eAAe,CAAC;IACjC,kBAAkB,EAAE,kBAAkB,CAAC;CACxC,CAAC"}
@@ -67,7 +67,9 @@ describe("presentDashboardCard personas", () => {
67
67
  expect(card.verdict?.posture).toBe("safe");
68
68
  expect(card.headline).toMatch(/patch upgrade/i);
69
69
  expect(card.headline).not.toMatch(/needs review/i);
70
- expect(card.verification.length).toBe(0);
70
+ expect(card.verification.length).toBeGreaterThan(0);
71
+ expect(card.verificationChannel).toBe("artifact");
72
+ expect(card.verification.some((v) => v.toLowerCase().includes("typecheck"))).toBe(true);
71
73
  });
72
74
  });
73
75
  describe("presentScanDetails usage paths", () => {
@@ -16,6 +16,7 @@ const personas = [
16
16
  density: "minimal",
17
17
  headlineMatch: /patch upgrade/i,
18
18
  headlineMustNot: /needs review/i,
19
+ verificationIncludes: ["typecheck"],
19
20
  },
20
21
  {
21
22
  name: "eslint",
@@ -34,6 +35,7 @@ const personas = [
34
35
  density: "minimal",
35
36
  headlineMatch: /patch upgrade/i,
36
37
  headlineMustNot: /needs review/i,
38
+ verificationIncludes: ["format"],
37
39
  },
38
40
  {
39
41
  name: "vitest",
@@ -1 +1 @@
1
- {"version":3,"file":"buildProfileFromAssessment.d.ts","sourceRoot":"","sources":["../../../src/presentation/profile/buildProfileFromAssessment.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,UAAU,EACV,4BAA4B,EAC7B,MAAM,wBAAwB,CAAC;AAEhC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAIjD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAiDpE,wBAAgB,0BAA0B,CACxC,UAAU,EAAE,UAAU,EACtB,YAAY,EAAE,4BAA4B,EAC1C,MAAM,EAAE,UAAU,GACjB,mBAAmB,CAuBrB"}
1
+ {"version":3,"file":"buildProfileFromAssessment.d.ts","sourceRoot":"","sources":["../../../src/presentation/profile/buildProfileFromAssessment.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,UAAU,EACV,4BAA4B,EAC7B,MAAM,wBAAwB,CAAC;AAEhC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAIjD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAoDpE,wBAAgB,0BAA0B,CACxC,UAAU,EAAE,UAAU,EACtB,YAAY,EAAE,4BAA4B,EAC1C,MAAM,EAAE,UAAU,GACjB,mBAAmB,CAuBrB"}
@@ -1,7 +1,7 @@
1
1
  import { narrativeIntensityToDensity } from "../../assessmentPresentationUtils.js";
2
2
  import { safeParseRepoIntelligence } from "../../repoIntelligenceSchema.js";
3
3
  import { scanSurfaceCopy } from "../../scanSurfaceCopy.js";
4
- import { collectVerificationFocus } from "../../assessmentProjection.js";
4
+ import { collectVerificationFocusForPresentation } from "../../assessmentProjection.js";
5
5
  function focalAnchorPackage(assessment) {
6
6
  const anchors = assessment.reviewFocalPoint.anchors;
7
7
  if (!anchors.length)
@@ -14,7 +14,7 @@ function focalAnchorPackage(assessment) {
14
14
  return token;
15
15
  }
16
16
  function buildInterpretation(assessment, presentation, result) {
17
- const verificationLabels = collectVerificationFocus(result);
17
+ const { focus: verificationLabels } = collectVerificationFocusForPresentation(presentation, result);
18
18
  const anchorPackage = focalAnchorPackage(assessment);
19
19
  const suppressRuntimeNarrative = presentation.reachVisibility === "hidden";
20
20
  let intent = "unknown_upgrade";
@@ -1 +1 @@
1
- {"version":3,"file":"projectAssessmentFields.d.ts","sourceRoot":"","sources":["../../src/presentation/projectAssessmentFields.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,4BAA4B,EAAE,MAAM,uCAAuC,CAAC;AAC1F,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,2CAA2C,CAAC;AAExF,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,sBAAsB,GAC7B,4BAA4B,CAW9B"}
1
+ {"version":3,"file":"projectAssessmentFields.d.ts","sourceRoot":"","sources":["../../src/presentation/projectAssessmentFields.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,4BAA4B,EAAE,MAAM,uCAAuC,CAAC;AAC1F,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,2CAA2C,CAAC;AAExF,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,sBAAsB,GAC7B,4BAA4B,CAgB9B"}
@@ -1,12 +1,14 @@
1
- import { collectVerificationFocus, projectReasoningLines, } from "../assessmentProjection.js";
1
+ import { collectVerificationFocusForPresentation, projectReasoningLines, } from "../assessmentProjection.js";
2
2
  export function projectAssessmentFields(bundle) {
3
3
  const { assessment, presentation, result } = bundle;
4
+ const { channel, focus } = collectVerificationFocusForPresentation(presentation, result);
4
5
  return {
5
6
  posture: assessment.posture,
6
7
  primaryConcern: assessment.primaryConcern,
7
8
  factors: [...assessment.factors],
8
9
  reasoning: projectReasoningLines(result),
9
- verificationFocus: collectVerificationFocus(result),
10
+ verificationFocus: focus,
11
+ verificationChannel: channel,
10
12
  reachVisibility: presentation.reachVisibility,
11
13
  narrativeIntensity: presentation.narrativeIntensity,
12
14
  };
@@ -85,6 +85,10 @@ describe("surfaceParity guardrail", () => {
85
85
  expect(s.details.verificationFocus).toEqual(s.fields.verificationFocus);
86
86
  expect(s.check.verificationFocus).toEqual(s.fields.verificationFocus);
87
87
  expect(s.comment.verificationFocus).toEqual(s.fields.verificationFocus);
88
+ expect(s.card.verificationChannel).toBe(s.fields.verificationChannel);
89
+ expect(s.details.verificationChannel).toBe(s.fields.verificationChannel);
90
+ expect(s.check.verificationChannel).toBe(s.fields.verificationChannel);
91
+ expect(s.comment.verificationChannel).toBe(s.fields.verificationChannel);
88
92
  });
89
93
  it(`${persona.name}: headline matches across card and details`, () => {
90
94
  const s = surfacesFor(persona.result);
@@ -133,6 +137,8 @@ describe("surfaceParity guardrail", () => {
133
137
  const ch26 = channelsById.get("validation-pr-26");
134
138
  expect(ch28.reachLabel).toBeUndefined();
135
139
  expect(ch29.reachLabel).toBeUndefined();
140
+ expect(ch28.verification.length).toBeGreaterThan(0);
141
+ expect(ch29.verification.length).toBeGreaterThan(0);
136
142
  expect(ch27.verification.length).toBeGreaterThan(0);
137
143
  expect(ch30.verification.length).toBeGreaterThan(0);
138
144
  expect(ch27.verification).not.toEqual(ch30.verification);
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=verificationChannelParity.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verificationChannelParity.test.d.ts","sourceRoot":"","sources":["../../src/presentation/verificationChannelParity.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,57 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { buildScanPresentationBundle } from "./orchestration/buildScanPresentationBundle.js";
3
+ import { presentDashboardCard } from "./presenters/presentDashboardCard.js";
4
+ import { presentScanDetails } from "./presenters/presentScanDetails.js";
5
+ import { presentGitHubCheckRun } from "./presenters/presentGitHubCheckRun.js";
6
+ import { presentGitHubPrComment } from "./presenters/presentGitHubPrComment.js";
7
+ import { projectAssessmentFields } from "./projectAssessmentFields.js";
8
+ import { scanResultFastifyRuntime, scanResultPrettier, scanResultTypescriptPatch, } from "./fixtures/presentationPersonaFixtures.js";
9
+ const SCAN_ID = "22222222-2222-4222-8222-222222222222";
10
+ const ORIGIN = "https://app.example.com";
11
+ describe("verification channel provenance parity", () => {
12
+ for (const persona of [
13
+ {
14
+ name: "fastify runtime",
15
+ result: scanResultFastifyRuntime,
16
+ channel: "runtime",
17
+ focusIncludes: "routes",
18
+ },
19
+ {
20
+ name: "typescript patch",
21
+ result: scanResultTypescriptPatch,
22
+ channel: "artifact",
23
+ focusIncludes: "typecheck",
24
+ },
25
+ {
26
+ name: "prettier",
27
+ result: scanResultPrettier,
28
+ channel: "artifact",
29
+ focusIncludes: "format",
30
+ },
31
+ ]) {
32
+ it(`${persona.name}: verificationChannel and focus match across surfaces`, () => {
33
+ const bundle = buildScanPresentationBundle({
34
+ result: persona.result,
35
+ pipelineStatus: "done",
36
+ });
37
+ const fields = projectAssessmentFields(bundle);
38
+ const card = presentDashboardCard(bundle);
39
+ const details = presentScanDetails(bundle, { scanId: SCAN_ID });
40
+ const check = presentGitHubCheckRun(bundle, {
41
+ scanId: SCAN_ID,
42
+ webAppOrigin: ORIGIN,
43
+ });
44
+ const comment = presentGitHubPrComment(bundle);
45
+ expect(fields.verificationChannel).toBe(persona.channel);
46
+ expect(card.verificationChannel).toBe(persona.channel);
47
+ expect(details.verificationChannel).toBe(persona.channel);
48
+ expect(check.verificationChannel).toBe(persona.channel);
49
+ expect(comment.verificationChannel).toBe(persona.channel);
50
+ expect(fields.verificationFocus).toEqual(card.verificationFocus);
51
+ expect(details.verificationFocus).toEqual(fields.verificationFocus);
52
+ expect(check.verificationFocus).toEqual(fields.verificationFocus);
53
+ expect(comment.verificationFocus).toEqual(fields.verificationFocus);
54
+ expect(fields.verificationFocus.some((f) => f.toLowerCase().includes(persona.focusIncludes.toLowerCase()))).toBe(true);
55
+ });
56
+ }
57
+ });
@@ -16,4 +16,36 @@ describe("repoIntelligenceWireSchema contract", () => {
16
16
  const joined = r.issues.join(" ");
17
17
  expect(joined.length).toBeGreaterThan(0);
18
18
  });
19
+ it("accepts optional lifecycleStages and promotedAreas on package rows (ABI 3)", () => {
20
+ const wire = {
21
+ packages: {
22
+ "acme-runtime-http-lib": {
23
+ runtimeSurface: "runtime",
24
+ reachability: "on_runtime_paths",
25
+ usage: {
26
+ packageName: "acme-runtime-http-lib",
27
+ files: ["apps/api/handlers/entry.ts"],
28
+ areas: [],
29
+ },
30
+ lifecycleStages: [
31
+ {
32
+ stage: "route_registration",
33
+ fileCount: 1,
34
+ evidenceRefs: ["import_path:apps/api/handlers/entry.ts"],
35
+ },
36
+ ],
37
+ promotedAreas: [
38
+ {
39
+ area: "api",
40
+ structuralAnchor: "http_surface",
41
+ evidenceRefs: ["import_path:apps/api/handlers/entry.ts"],
42
+ },
43
+ ],
44
+ },
45
+ },
46
+ };
47
+ const validated = validateRepoIntelligenceWire(wire);
48
+ expect(validated.packages["acme-runtime-http-lib"]?.lifecycleStages?.length).toBe(1);
49
+ expect(validated.packages["acme-runtime-http-lib"]?.promotedAreas?.length).toBe(1);
50
+ });
19
51
  });
@@ -9,7 +9,7 @@ import { z } from "zod";
9
9
  import type { ScanResult } from "./types.js";
10
10
  import type { BlastRadiusLevel } from "./scanNarrativeFacts.js";
11
11
  /** Bump when wire schema changes incompatibly. */
12
- export declare const REPO_INTELLIGENCE_ABI: "2";
12
+ export declare const REPO_INTELLIGENCE_ABI: "3";
13
13
  /** Strict canonical wire schema — single source of truth. */
14
14
  export declare const repoIntelligenceWireSchema: z.ZodObject<{
15
15
  packages: z.ZodRecord<z.ZodString, z.ZodObject<{
@@ -35,13 +35,13 @@ export declare const repoIntelligenceWireSchema: z.ZodObject<{
35
35
  }, z.core.$strip>;
36
36
  areas: z.ZodOptional<z.ZodArray<z.ZodString>>;
37
37
  dependencyClass: z.ZodOptional<z.ZodEnum<{
38
+ lint: "lint";
39
+ format: "format";
38
40
  unknown: "unknown";
39
41
  runtime: "runtime";
40
42
  build: "build";
41
43
  test: "test";
42
44
  tooling: "tooling";
43
- lint: "lint";
44
- format: "format";
45
45
  ci: "ci";
46
46
  }>>;
47
47
  packageRole: z.ZodOptional<z.ZodEnum<{
@@ -70,10 +70,10 @@ export declare const repoIntelligenceWireSchema: z.ZodObject<{
70
70
  possible: "possible";
71
71
  }>>;
72
72
  expectedImpact: z.ZodOptional<z.ZodEnum<{
73
+ typecheck: "typecheck";
73
74
  unknown: "unknown";
74
75
  runtime: "runtime";
75
76
  build_time: "build_time";
76
- typecheck: "typecheck";
77
77
  test_time: "test_time";
78
78
  development_only: "development_only";
79
79
  }>>;
@@ -101,6 +101,24 @@ export declare const repoIntelligenceWireSchema: z.ZodObject<{
101
101
  }>;
102
102
  registryEntryId: z.ZodOptional<z.ZodString>;
103
103
  }, z.core.$strip>>;
104
+ lifecycleStages: z.ZodOptional<z.ZodArray<z.ZodObject<{
105
+ stage: z.ZodString;
106
+ fileCount: z.ZodNumber;
107
+ evidenceRefs: z.ZodArray<z.ZodString>;
108
+ }, z.core.$strip>>>;
109
+ promotedAreas: z.ZodOptional<z.ZodArray<z.ZodObject<{
110
+ area: z.ZodString;
111
+ structuralAnchor: z.ZodOptional<z.ZodEnum<{
112
+ http_surface: "http_surface";
113
+ auth_surface: "auth_surface";
114
+ orm_surface: "orm_surface";
115
+ queue_surface: "queue_surface";
116
+ type_surface: "type_surface";
117
+ build_surface: "build_surface";
118
+ testing_surface: "testing_surface";
119
+ }>>;
120
+ evidenceRefs: z.ZodArray<z.ZodString>;
121
+ }, z.core.$strip>>>;
104
122
  }, z.core.$strip>>;
105
123
  packageUsage: z.ZodOptional<z.ZodArray<z.ZodObject<{
106
124
  packageName: z.ZodString;
@@ -1 +1 @@
1
- {"version":3,"file":"repoIntelligenceSchema.d.ts","sourceRoot":"","sources":["../src/repoIntelligenceSchema.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAEhE,kDAAkD;AAClD,eAAO,MAAM,qBAAqB,EAAG,GAAY,CAAC;AA+HlD,6DAA6D;AAC7D,eAAO,MAAM,0BAA0B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBASrC,CAAC;AAEH,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,0BAA0B,CAAC,CAAC;AAE1E,MAAM,MAAM,4BAA4B,GAAG;IACzC,EAAE,EAAE,IAAI,CAAC;IACT,KAAK,EAAE,gBAAgB,CAAC;CACzB,CAAC;AAEF,MAAM,MAAM,4BAA4B,GAAG;IACzC,EAAE,EAAE,KAAK,CAAC;IACV,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF,MAAM,MAAM,2BAA2B,GACnC,4BAA4B,GAC5B,4BAA4B,CAAC;AAQjC,wBAAgB,6BAA6B,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,CAUlE;AAED,wBAAgB,yBAAyB,CACvC,GAAG,EAAE,OAAO,GACX,2BAA2B,CAyC7B;AAED,uEAAuE;AACvE,wBAAgB,4BAA4B,CAAC,GAAG,EAAE,OAAO,GAAG,gBAAgB,CAM3E;AAED,mFAAmF;AACnF,wBAAgB,uCAAuC,CACrD,IAAI,EAAE,UAAU,GACf,IAAI,CAGN;AAED,wBAAgB,cAAc,CAC5B,KAAK,EAAE,gBAAgB,GAAG,SAAS,GAClC,gBAAgB,GAAG,IAAI,CAKzB"}
1
+ {"version":3,"file":"repoIntelligenceSchema.d.ts","sourceRoot":"","sources":["../src/repoIntelligenceSchema.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAEhE,kDAAkD;AAClD,eAAO,MAAM,qBAAqB,EAAG,GAAY,CAAC;AAuJlD,6DAA6D;AAC7D,eAAO,MAAM,0BAA0B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBASrC,CAAC;AAEH,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,0BAA0B,CAAC,CAAC;AAE1E,MAAM,MAAM,4BAA4B,GAAG;IACzC,EAAE,EAAE,IAAI,CAAC;IACT,KAAK,EAAE,gBAAgB,CAAC;CACzB,CAAC;AAEF,MAAM,MAAM,4BAA4B,GAAG;IACzC,EAAE,EAAE,KAAK,CAAC;IACV,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF,MAAM,MAAM,2BAA2B,GACnC,4BAA4B,GAC5B,4BAA4B,CAAC;AAQjC,wBAAgB,6BAA6B,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,CAUlE;AAED,wBAAgB,yBAAyB,CACvC,GAAG,EAAE,OAAO,GACX,2BAA2B,CAyC7B;AAED,uEAAuE;AACvE,wBAAgB,4BAA4B,CAAC,GAAG,EAAE,OAAO,GAAG,gBAAgB,CAM3E;AAED,mFAAmF;AACnF,wBAAgB,uCAAuC,CACrD,IAAI,EAAE,UAAU,GACf,IAAI,CAGN;AAED,wBAAgB,cAAc,CAC5B,KAAK,EAAE,gBAAgB,GAAG,SAAS,GAClC,gBAAgB,GAAG,IAAI,CAKzB"}
@@ -7,7 +7,7 @@
7
7
  */
8
8
  import { z } from "zod";
9
9
  /** Bump when wire schema changes incompatibly. */
10
- export const REPO_INTELLIGENCE_ABI = "2";
10
+ export const REPO_INTELLIGENCE_ABI = "3";
11
11
  const surfaceKindSchema = z.enum(["runtime", "build", "test", "unknown"]);
12
12
  const reachabilityKindSchema = z.enum([
13
13
  "on_runtime_paths",
@@ -86,6 +86,25 @@ const semanticDiagnosticSchema = z.object({
86
86
  after: z.record(z.string(), z.unknown()),
87
87
  reason: z.string().min(1),
88
88
  });
89
+ const structuralRoleWireSchema = z.enum([
90
+ "http_surface",
91
+ "auth_surface",
92
+ "orm_surface",
93
+ "queue_surface",
94
+ "type_surface",
95
+ "build_surface",
96
+ "testing_surface",
97
+ ]);
98
+ const wireLifecycleStageProjectionSchema = z.object({
99
+ stage: z.string().min(1),
100
+ fileCount: z.number().int().nonnegative(),
101
+ evidenceRefs: z.array(z.string()),
102
+ });
103
+ const wirePromotedAreaProjectionSchema = z.object({
104
+ area: z.string().min(1),
105
+ structuralAnchor: structuralRoleWireSchema.optional(),
106
+ evidenceRefs: z.array(z.string()),
107
+ });
89
108
  const packageIntelWireSchema = z.object({
90
109
  runtimeSurface: surfaceKindSchema,
91
110
  reachability: reachabilityKindSchema,
@@ -101,6 +120,8 @@ const packageIntelWireSchema = z.object({
101
120
  verificationFocus: z.array(z.string()).optional(),
102
121
  suppressRuntimeNarrative: z.boolean().optional(),
103
122
  classificationProvenance: classificationProvenanceSchema.optional(),
123
+ lifecycleStages: z.array(wireLifecycleStageProjectionSchema).optional(),
124
+ promotedAreas: z.array(wirePromotedAreaProjectionSchema).optional(),
104
125
  });
105
126
  const areaSchema = z.object({
106
127
  id: z.string().min(1),
@@ -156,10 +156,16 @@ export declare const engineOutputScanResultSchema: z.ZodObject<{
156
156
  very_low: "very_low";
157
157
  moderate: "moderate";
158
158
  }>;
159
+ entryPointFiles: z.ZodOptional<z.ZodArray<z.ZodString>>;
159
160
  }, z.core.$strip>;
160
161
  verificationScope: z.ZodObject<{
161
162
  packages: z.ZodArray<z.ZodString>;
162
163
  focus: z.ZodArray<z.ZodString>;
164
+ artifactGrounded: z.ZodOptional<z.ZodObject<{
165
+ packages: z.ZodArray<z.ZodString>;
166
+ focus: z.ZodArray<z.ZodString>;
167
+ artifactPaths: z.ZodArray<z.ZodString>;
168
+ }, z.core.$strip>>;
163
169
  }, z.core.$strip>;
164
170
  posture: z.ZodEnum<{
165
171
  safe: "safe";
@@ -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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;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"}
1
+ {"version":3,"file":"scanResultSchema.d.ts","sourceRoot":"","sources":["../src/scanResultSchema.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,uBAAuB,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAEtE,wGAAwG;AACxG,eAAO,MAAM,eAAe,EAAG,GAAY,CAAC;AAE5C,+EAA+E;AAC/E,eAAO,MAAM,sBAAsB,EAAG,GAAY,CAAC;AAmBnD;;;GAGG;AACH,wBAAgB,yBAAyB,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAc/D;AAED;;;;GAIG;AACH,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBA8Bb,CAAC;AAUjB;;;GAGG;AACH,eAAO,MAAM,4BAA4B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAMvC,CAAC;AAEH,MAAM,MAAM,kCAAkC,GAAG;IAC/C,EAAE,EAAE,KAAK,CAAC;IACV,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,kCAAkC,GAAG;IAC/C,EAAE,EAAE,IAAI,CAAC;IACT,MAAM,EAAE,uBAAuB,CAAC;CACjC,CAAC;AAEF,wBAAgB,+BAA+B,CAC7C,IAAI,EAAE,OAAO,GACZ,kCAAkC,GAAG,kCAAkC,CAezE;AAED,uFAAuF;AACvF,wBAAgB,kCAAkC,CAChD,IAAI,EAAE,OAAO,GACZ,uBAAuB,CAMzB;AAED,MAAM,MAAM,sBAAsB,GAAG;IACnC,EAAE,EAAE,KAAK,CAAC;IACV,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,sBAAsB,GAAG;IACnC,EAAE,EAAE,IAAI,CAAC;IACT,MAAM,EAAE,UAAU,CAAC;CACpB,CAAC;AAEF,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,OAAO,GACZ,sBAAsB,GAAG,sBAAsB,CAajD;AAED,yEAAyE;AACzE,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,OAAO,GAAG,UAAU,CAMhE"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mergesignal/shared",
3
- "version": "0.9.1",
3
+ "version": "0.11.0",
4
4
  "description": "MergeSignal shared scan contract, presentation policy, and trusted validation",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -38,7 +38,7 @@
38
38
  "test": "vitest run"
39
39
  },
40
40
  "dependencies": {
41
- "@mergesignal/contracts": "0.1.0",
41
+ "@mergesignal/contracts": "catalog:",
42
42
  "zod": "^4.4.3"
43
43
  },
44
44
  "devDependencies": {