@shapeshift-labs/frontier-lang-compiler 0.2.100 → 0.2.102

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 (47) hide show
  1. package/dist/declarations/bidirectional-target-change-evidence.d.ts +299 -0
  2. package/dist/declarations/bidirectional-target-change.d.ts +19 -120
  3. package/dist/declarations/import-adapter-core.d.ts +6 -0
  4. package/dist/declarations/native-project-admission.d.ts +43 -22
  5. package/dist/declarations/semantic-edit-replay-diagnostics.d.ts +24 -0
  6. package/dist/declarations/semantic-edit-script.d.ts +20 -15
  7. package/dist/declarations/semantic-lineage.d.ts +3 -21
  8. package/dist/declarations/semantic-merge-candidates.d.ts +39 -0
  9. package/dist/declarations/semantic-sidecar-admission.d.ts +14 -0
  10. package/dist/declarations/semantic-sidecar.d.ts +12 -14
  11. package/dist/internal/index-impl/bidirectionalTargetRoundtripEvidence.js +200 -0
  12. package/dist/internal/index-impl/createBidirectionalTargetChangeRecord.js +62 -17
  13. package/dist/internal/index-impl/createLightweightNativeImport.js +9 -1
  14. package/dist/internal/index-impl/createNativeSourcePreservation.js +16 -1
  15. package/dist/internal/index-impl/createProjectImportAdmissionRecord.js +151 -1
  16. package/dist/internal/index-impl/createSemanticImportSidecar.js +5 -0
  17. package/dist/internal/index-impl/createSemanticImportSidecarAdmission.js +29 -11
  18. package/dist/internal/index-impl/importNativeSource.js +14 -14
  19. package/dist/internal/index-impl/nativeChangeProjectionEndpoint.js +56 -16
  20. package/dist/internal/index-impl/nativeImportSemanticIndex.js +33 -0
  21. package/dist/internal/index-impl/projectImportAdmissionMergeScore.js +26 -74
  22. package/dist/internal/index-impl/projectImportAdmissionProjectionCoverage.js +74 -0
  23. package/dist/internal/index-impl/projectSemanticEditScriptToSource.js +39 -13
  24. package/dist/internal/index-impl/replaySemanticEditProjection.js +65 -23
  25. package/dist/internal/index-impl/semanticEditInsertionAnchors.js +8 -5
  26. package/dist/internal/index-impl/semanticEditReplayDiagnostics.js +167 -0
  27. package/dist/internal/index-impl/semanticEditSourceRanges.js +94 -15
  28. package/dist/internal/index-impl/semanticHistoryLineageResolution.js +21 -2
  29. package/dist/internal/index-impl/semanticLineageHashEvidence.js +97 -0
  30. package/dist/internal/index-impl/semanticLineageInferenceMatching.js +8 -0
  31. package/dist/internal/index-impl/semanticLineageResolutionRecords.js +18 -1
  32. package/dist/internal/index-impl/semanticMergeCandidateRecords.js +22 -2
  33. package/dist/internal/index-impl/semanticMergeCandidateScoreFacets.js +221 -0
  34. package/dist/internal/index-impl/semanticPatchBundleOverlaps.js +23 -1
  35. package/dist/internal/index-impl/sourcePreservationFromProjectionContext.js +9 -2
  36. package/dist/native-import-language-profiles.js +10 -2
  37. package/dist/native-region-scanner-js-helpers.js +8 -2
  38. package/dist/native-region-scanner-js-imports.js +7 -0
  39. package/dist/native-region-scanner-js.js +4 -4
  40. package/dist/native-region-scanner.js +2 -1
  41. package/dist/semantic-import-regions.js +18 -5
  42. package/dist/semantic-import-sidecar-admission-types.d.ts +14 -0
  43. package/dist/semantic-import-sidecar-entry.js +151 -7
  44. package/dist/semantic-import-sidecar-types.d.ts +18 -13
  45. package/dist/semantic-import-source-preservation-utils.js +55 -0
  46. package/dist/semantic-import-source-preservation.js +98 -3
  47. package/package.json +1 -1
@@ -24,7 +24,7 @@ import type {
24
24
  UniversalAstLayerMap,
25
25
  UniversalAstLayerRecord
26
26
  } from '@shapeshift-labs/frontier-lang-kernel';
27
- import type { SemanticImportSidecarAdmission, SemanticImportSidecarQuality } from './semantic-sidecar-admission.js';
27
+ import type { SemanticImportSidecarAdmission, SemanticImportSidecarQuality, SemanticImportSidecarQualityRecord } from './semantic-sidecar-admission.js';
28
28
  import type { SemanticMergeCandidateAdmissionRecord, SemanticMergeCandidateProjectionRisk } from './semantic-merge-candidates.js';
29
29
  import type { SemanticMergeConflictClass, SemanticMergeConflictSummary } from './semantic-merge-conflicts.js';
30
30
  import type { SemanticImportImpactSummary } from './semantic-impact.js';
@@ -52,7 +52,6 @@ import type { JavaAstNativeImporterAdapterOptions, KotlinPsiNativeImporterAdapte
52
52
  import type { NativeTargetProjectionAdapterCoverageInput, NativeTargetProjectionAdapterSummary, NativeTargetProjectionAdapterInput, NativeTargetProjectionAdapterResult, NativeTargetProjectionAdapter, NativeTargetProjectionAdapterResolverInput, NativeTargetProjectionResult } from './target-adapters.js';
53
53
  import type { NativeProjectSourceInput, ImportNativeProjectOptions, NativeProjectImportResult, NativeSourceProjectionMode, ProjectNativeImportToSourceOptions, NativeSourceProjectionDeclaration, NativeSourceProjectionResult, NativeSourceCompileOutputMode, CompileNativeSourceOptions, NativeSourceCompileResult } from './native-project.js';
54
54
  import type { NativeImportRoundtripReadinessStatus, NativeImportRoundtripReadinessOptions, NativeImportRoundtripReadinessClassification } from './roundtrip.js';
55
-
56
55
  export interface SemanticImportOwnershipRegion {
57
56
  readonly id: string;
58
57
  readonly key: string;
@@ -71,7 +70,6 @@ export interface SemanticImportOwnershipRegion {
71
70
  readonly mergePolicy?: string;
72
71
  readonly metadata?: Record<string, unknown>;
73
72
  }
74
-
75
73
  export interface SemanticImportSidecarSymbol {
76
74
  readonly id: string;
77
75
  readonly name?: string;
@@ -87,7 +85,6 @@ export interface SemanticImportSidecarSymbol {
87
85
  readonly ownershipRegionKind?: NativeImportRegionTaxonomyKind;
88
86
  readonly readiness: SemanticMergeReadiness;
89
87
  }
90
-
91
88
  export interface SemanticImportRegionTaxonomySummary {
92
89
  readonly kinds: readonly NativeImportRegionTaxonomyKind[];
93
90
  readonly presentKinds: readonly NativeImportRegionTaxonomyKind[];
@@ -95,12 +92,12 @@ export interface SemanticImportRegionTaxonomySummary {
95
92
  readonly keys: readonly string[];
96
93
  readonly keysByKind: Readonly<Record<string, readonly string[]>>;
97
94
  }
98
-
99
95
  export interface SemanticImportPatchHint {
100
96
  readonly id: string;
101
97
  readonly kind: 'source-region-patch' | string;
102
98
  readonly ownershipRegionId: string;
103
99
  readonly ownershipKey: string;
100
+ readonly operation: string;
104
101
  readonly sourcePath?: string;
105
102
  readonly sourceHash?: string;
106
103
  readonly sourceSpan?: SourceSpan;
@@ -113,7 +110,6 @@ export interface SemanticImportPatchHint {
113
110
  readonly requiresSourceMap: boolean;
114
111
  };
115
112
  }
116
-
117
113
  export interface SemanticImportSidecarImportEntry {
118
114
  readonly id: string;
119
115
  readonly language?: FrontierSourceLanguage | string;
@@ -135,11 +131,17 @@ export interface SemanticImportSidecarImportEntry {
135
131
  readonly proofSpec: SemanticImportSidecarProofSpecSummary;
136
132
  readonly paradigmSemantics: SemanticImportSidecarParadigmSemanticsSummary;
137
133
  readonly dependencyRelationCount: number; readonly dependencyPredicates: readonly string[];
134
+ readonly semanticFactCount?: number;
135
+ readonly semanticFactPredicates?: readonly string[];
136
+ readonly semanticFactSummary?: Readonly<Record<string, number>>;
137
+ readonly patchHintCount?: number;
138
+ readonly patchHintOperations?: readonly string[];
139
+ readonly patchHints?: readonly SemanticImportPatchHint[];
138
140
  readonly readiness: SemanticMergeReadiness;
139
141
  readonly emptySemanticIndex: boolean;
142
+ readonly qualityRecord: SemanticImportSidecarQualityRecord;
140
143
  readonly regionTaxonomy?: SemanticImportRegionTaxonomySummary;
141
144
  }
142
-
143
145
  export interface SemanticImportSidecarSourcePreservationRecord {
144
146
  readonly id: string;
145
147
  readonly level: SourcePreservationLevel;
@@ -157,7 +159,6 @@ export interface SemanticImportSidecarSourcePreservationRecord {
157
159
  readonly evidenceIds: readonly string[];
158
160
  readonly reasons: readonly string[];
159
161
  }
160
-
161
162
  export interface SemanticImportSidecarUniversalAstLayerSummary {
162
163
  readonly total: number;
163
164
  readonly names: readonly string[];
@@ -165,7 +166,6 @@ export interface SemanticImportSidecarUniversalAstLayerSummary {
165
166
  readonly byName: Readonly<Record<string, number>>;
166
167
  readonly empty: boolean;
167
168
  }
168
-
169
169
  export interface SemanticImportSidecarProofSpecSummary {
170
170
  readonly total: number;
171
171
  readonly ids: readonly string[];
@@ -194,7 +194,6 @@ export interface SemanticImportSidecarProofSpecSummary {
194
194
  readonly byArtifactKind: Readonly<Record<string, number>>;
195
195
  readonly empty: boolean;
196
196
  }
197
-
198
197
  export interface SemanticImportSidecarParadigmSemanticsSummary {
199
198
  readonly total: number;
200
199
  readonly ids: readonly string[];
@@ -230,14 +229,12 @@ export interface SemanticImportSidecarParadigmSemanticsSummary {
230
229
  readonly hasLowering: boolean;
231
230
  readonly empty: boolean;
232
231
  }
233
-
234
232
  export interface SemanticImportDependencySummary {
235
233
  readonly total: number; readonly calls: number; readonly uses: number; readonly references: number;
236
234
  readonly imports: number; readonly extends: number; readonly implements: number; readonly includes: number; readonly requires: number;
237
235
  readonly byPredicate: Readonly<Record<string, number>>; readonly predicates: readonly string[];
238
236
  readonly ids: readonly string[]; readonly sourceSymbolIds: readonly string[]; readonly targetSymbolIds: readonly string[];
239
237
  }
240
-
241
238
  export interface SemanticImportSidecar {
242
239
  readonly kind: 'frontier.lang.semanticImportSidecar';
243
240
  readonly version: 1;
@@ -313,8 +310,9 @@ export interface SemanticImportSidecar {
313
310
  readonly semanticImpactRecords: number; readonly semanticImpactHighRiskRecords: number; readonly semanticImpactRequiredVerificationSteps: number;
314
311
  readonly patchHints: number;
315
312
  readonly evidenceWarnings: number;
316
- readonly semanticImportExpected: boolean; readonly semanticImportExpectedSatisfied: boolean; readonly semanticImportExpectedMissingReasonCodes: readonly string[];
313
+ readonly semanticImportExpected: boolean; readonly semanticImportExpectedEmpty: boolean; readonly semanticImportExpectedSatisfied: boolean; readonly semanticImportExpectedMissingReasonCodes: readonly string[];
314
+ readonly semanticImportRecordClassification: string; readonly semanticImportRecordReasonCode: string; readonly semanticImportRecordAction: string;
317
315
  readonly readiness: SemanticMergeReadiness; readonly emptySemanticIndex: boolean;
318
316
  };
319
317
  readonly metadata?: Record<string, unknown>; }
320
- export interface SemanticImportSidecarOptions { readonly id?: string; readonly generatedAt?: number; readonly regionPrefix?: string; readonly targetPath?: string; readonly expected?: boolean; readonly semanticImportExpected?: boolean; readonly metadata?: Record<string, unknown>; }
318
+ export interface SemanticImportSidecarOptions { readonly id?: string; readonly generatedAt?: number; readonly regionPrefix?: string; readonly targetPath?: string; readonly expected?: boolean; readonly semanticImportExpected?: boolean; readonly expectedEmpty?: boolean; readonly semanticImportExpectedEmpty?: boolean; readonly metadata?: Record<string, unknown>; }
@@ -0,0 +1,200 @@
1
+ import { idFragment, uniqueRecordsById, uniqueStrings } from '../../native-import-utils.js';
2
+ import { sourceHash } from './bidirectionalTargetChangeRecordInternals.js';
3
+
4
+ export function summarizeSourceMapBackprojection(matches) {
5
+ const links = matches.flatMap((match) => match.sourceMapLinks ?? []);
6
+ return {
7
+ sourceMapBackedMatches: matches.filter((match) => (match.sourceMapLinks ?? []).length > 0).length,
8
+ sourceMapLinks: links.length,
9
+ sourceMapIds: uniqueStrings(links.map((link) => link.sourceMapId)),
10
+ sourceMapMappingIds: uniqueStrings(links.map((link) => link.sourceMapMappingId))
11
+ };
12
+ }
13
+
14
+ export function createRoundtripEvidence(context) {
15
+ const sourceMapLinks = uniqueRecordsById(context.sourceAnchorMatches.flatMap((match) => match.sourceMapLinks ?? []));
16
+ const targetProjectionLinks = uniqueRecordsById((context.targetChangeSet.changedRegions ?? [])
17
+ .flatMap((region) => array(region.metadata?.changedRegionProjection?.sourceMapLinks)));
18
+ const sourceAnchors = uniqueRecordsByKey(context.sourceAnchorMatches.flatMap((match) => match.sourceAnchors ?? []));
19
+ const lineageResolutions = uniqueRecordsById(context.sourceAnchorMatches.flatMap((match) => match.lineageResolutions ?? []));
20
+ return {
21
+ schema: 'frontier.lang.bidirectionalTargetChangeRoundtripEvidence.v1',
22
+ version: 1,
23
+ id: `roundtrip_evidence_${idFragment(context.id)}`,
24
+ evidenceId: context.evidenceId,
25
+ sourcePatchBundleId: context.sourcePatchBundleId,
26
+ historyRecordId: context.historyRecordId,
27
+ source: sourceIdentity(context.source),
28
+ target: targetChangeIdentity(context.targetChangeSet),
29
+ targetRegions: (context.targetChangeSet.changedRegions ?? []).map(targetRegionIdentity),
30
+ sourceAnchorMatches: context.sourceAnchorMatches.map(matchIdentity),
31
+ sourceAnchors,
32
+ sourceMapEvidence: {
33
+ ...context.sourceMapBackprojection,
34
+ sourceMapLinkIds: uniqueStrings(sourceMapLinks.map((link) => link.id)),
35
+ staleSourceMapLinkIds: uniqueStrings(context.targetPortability.staleSourceMapLinkIds),
36
+ targetProjectionSourceMapLinks: targetProjectionLinks.length,
37
+ targetProjectionSourceMapLinkIds: uniqueStrings(targetProjectionLinks.map((link) => link.id)),
38
+ targetProjectionSourceMapIds: uniqueStrings(targetProjectionLinks.map((link) => link.sourceMapId)),
39
+ targetProjectionSourceMapMappingIds: uniqueStrings(targetProjectionLinks.map((link) => link.sourceMapMappingId))
40
+ },
41
+ lineageEvidence: {
42
+ lineageResolutionIds: uniqueStrings(lineageResolutions.map((resolution) => resolution.id)),
43
+ lineageEventIds: uniqueStrings(lineageResolutions.flatMap((resolution) => resolution.traversedEventIds ?? [])),
44
+ lineageEvidenceIds: uniqueStrings(lineageResolutions.flatMap((resolution) => resolution.evidenceIds ?? [])),
45
+ lineageProofIds: uniqueStrings(lineageResolutions.flatMap((resolution) => resolution.proofIds ?? [])),
46
+ lineageReasonCodes: uniqueStrings(lineageResolutions.flatMap((resolution) => resolution.reasonCodes ?? []))
47
+ },
48
+ targetPortability: {
49
+ status: context.targetPortability.status,
50
+ action: context.targetPortability.action,
51
+ readiness: context.targetPortability.readiness,
52
+ reasonCodes: context.targetPortability.reasonCodes,
53
+ conflictKeys: context.targetPortability.conflictKeys
54
+ },
55
+ admission: {
56
+ status: context.readiness === 'blocked' ? 'blocked' : 'needs-review',
57
+ readiness: context.readiness,
58
+ action: context.targetPortability.action,
59
+ reasonCodes: context.reasons,
60
+ conflictKeys: uniqueStrings([
61
+ ...array(context.targetPortability.conflictKeys),
62
+ ...context.sourceAnchorMatches.flatMap((match) => match.conflictKeys ?? [])
63
+ ]),
64
+ evidenceIds: [context.evidenceId],
65
+ reviewRequired: true,
66
+ autoMergeClaim: false,
67
+ semanticEquivalenceClaim: false
68
+ },
69
+ reviewRequired: true,
70
+ autoMergeClaim: false,
71
+ semanticEquivalenceClaim: false
72
+ };
73
+ }
74
+
75
+ export function createSemanticMergeAdmissionEvidence(context) {
76
+ return {
77
+ schema: 'frontier.lang.bidirectionalTargetChangeSemanticMergeAdmission.v1',
78
+ version: 1,
79
+ id: `semantic_merge_admission_${idFragment(context.id)}_target_change`,
80
+ evidenceIds: [context.evidenceId],
81
+ sourcePatchBundleId: context.sourcePatchBundleId,
82
+ historyRecordId: context.historyRecordId,
83
+ targetChangeSetId: context.targetChangeSet.id,
84
+ targetPatchId: context.targetChangeSet.patch?.id,
85
+ targetMergeCandidateId: context.targetChangeSet.mergeCandidate?.id,
86
+ readiness: context.readiness,
87
+ status: context.readiness === 'blocked' ? 'blocked' : 'needs-review',
88
+ action: context.targetPortability.action,
89
+ reasonCodes: context.reasons,
90
+ conflictKeys: context.roundtripEvidence.admission.conflictKeys,
91
+ sourceAnchorMatchIds: uniqueStrings(context.sourceAnchorMatches.map((match) => match.id)),
92
+ sourceAnchorKeys: uniqueStrings(context.roundtripEvidence.sourceAnchors.map((anchor) => anchor.key)),
93
+ targetRegionKeys: uniqueStrings(context.roundtripEvidence.targetRegions.map((region) => region.key)),
94
+ sourceMapLinkIds: context.roundtripEvidence.sourceMapEvidence.sourceMapLinkIds,
95
+ sourceMapIds: context.roundtripEvidence.sourceMapEvidence.sourceMapIds,
96
+ sourceMapMappingIds: context.roundtripEvidence.sourceMapEvidence.sourceMapMappingIds,
97
+ staleSourceMapLinkIds: context.roundtripEvidence.sourceMapEvidence.staleSourceMapLinkIds,
98
+ targetProjectionSourceMapLinkIds: context.roundtripEvidence.sourceMapEvidence.targetProjectionSourceMapLinkIds,
99
+ targetProjectionSourceMapMappingIds: context.roundtripEvidence.sourceMapEvidence.targetProjectionSourceMapMappingIds,
100
+ lineageResolutionIds: context.roundtripEvidence.lineageEvidence.lineageResolutionIds,
101
+ reviewRequired: true,
102
+ autoMergeClaim: false,
103
+ semanticEquivalenceClaim: false
104
+ };
105
+ }
106
+
107
+ function sourceIdentity(source) {
108
+ return compactRecord({
109
+ importId: source?.id,
110
+ language: source?.language,
111
+ sourcePath: source?.sourcePath,
112
+ sourceHash: sourceHash(source),
113
+ nativeSourceId: source?.nativeSource?.id,
114
+ nativeAstId: source?.nativeAst?.id,
115
+ semanticIndexId: source?.semanticIndex?.id,
116
+ universalAstId: source?.universalAst?.id,
117
+ sourceMapIds: uniqueStrings((source?.sourceMaps ?? []).map((sourceMap) => sourceMap?.id))
118
+ });
119
+ }
120
+
121
+ function targetChangeIdentity(targetChangeSet) {
122
+ return compactRecord({
123
+ changeSetId: targetChangeSet.id,
124
+ language: targetChangeSet.language,
125
+ sourcePath: targetChangeSet.sourcePath,
126
+ beforeHash: targetChangeSet.beforeHash,
127
+ afterHash: targetChangeSet.afterHash,
128
+ beforeImportId: targetChangeSet.before?.id,
129
+ afterImportId: targetChangeSet.after?.id,
130
+ beforeNativeSourceId: targetChangeSet.before?.nativeSource?.id,
131
+ afterNativeSourceId: targetChangeSet.after?.nativeSource?.id,
132
+ beforeNativeAstId: targetChangeSet.before?.nativeAst?.id,
133
+ afterNativeAstId: targetChangeSet.after?.nativeAst?.id,
134
+ beforeSemanticIndexId: targetChangeSet.before?.semanticIndex?.id,
135
+ afterSemanticIndexId: targetChangeSet.after?.semanticIndex?.id,
136
+ patchId: targetChangeSet.patch?.id,
137
+ mergeCandidateId: targetChangeSet.mergeCandidate?.id,
138
+ sourceMapIds: uniqueStrings((targetChangeSet.sourceMaps ?? []).map((sourceMap) => sourceMap?.id))
139
+ });
140
+ }
141
+
142
+ function targetRegionIdentity(region) {
143
+ const projection = region.metadata?.changedRegionProjection;
144
+ return compactRecord({
145
+ id: region.id,
146
+ key: region.key,
147
+ conflictKey: region.conflictKey,
148
+ changeKind: region.changeKind,
149
+ regionKind: region.regionKind,
150
+ language: region.language,
151
+ sourcePath: region.sourcePath,
152
+ sourceHash: region.sourceHash,
153
+ symbolId: region.symbolId,
154
+ symbolName: region.symbolName ?? region.name,
155
+ sourceSpan: region.sourceSpan,
156
+ changedRegionProjectionId: projection?.id,
157
+ beforeIdentity: projection?.before?.identity,
158
+ afterIdentity: projection?.after?.identity,
159
+ sourceMapLinkIds: uniqueStrings(array(projection?.sourceMapLinks).map((link) => link.id)),
160
+ sourceMapIds: uniqueStrings(array(projection?.sourceMapLinks).map((link) => link.sourceMapId)),
161
+ sourceMapMappingIds: uniqueStrings(array(projection?.sourceMapLinks).map((link) => link.sourceMapMappingId))
162
+ });
163
+ }
164
+
165
+ function matchIdentity(match) {
166
+ return compactRecord({
167
+ id: match.id,
168
+ status: match.status,
169
+ targetRegionKey: match.targetRegion?.key,
170
+ targetRegionConflictKey: match.targetRegion?.conflictKey,
171
+ sourceAnchorKeys: uniqueStrings((match.sourceAnchors ?? []).map((anchor) => anchor.key)),
172
+ sourceMapLinkIds: uniqueStrings((match.sourceMapLinks ?? []).map((link) => link.id)),
173
+ sourceMapMappingIds: uniqueStrings((match.sourceMapLinks ?? []).map((link) => link.sourceMapMappingId)),
174
+ lineageResolutionIds: uniqueStrings((match.lineageResolutions ?? []).map((resolution) => resolution.id)),
175
+ portabilityStatus: match.portability?.status,
176
+ portabilityAction: match.portability?.action,
177
+ reasonCodes: match.reasonCodes,
178
+ conflictKeys: match.conflictKeys
179
+ });
180
+ }
181
+
182
+ function uniqueRecordsByKey(records) {
183
+ const seen = new Set();
184
+ const result = [];
185
+ for (const record of records ?? []) {
186
+ const key = record?.key ?? record?.id;
187
+ if (!key || seen.has(key)) continue;
188
+ seen.add(key);
189
+ result.push(record);
190
+ }
191
+ return result;
192
+ }
193
+
194
+ function array(value) {
195
+ return value === undefined || value === null ? [] : Array.isArray(value) ? value : [value];
196
+ }
197
+
198
+ function compactRecord(value) {
199
+ return Object.fromEntries(Object.entries(value ?? {}).filter(([, entry]) => entry !== undefined && (!Array.isArray(entry) || entry.length > 0)));
200
+ }
@@ -9,6 +9,7 @@ import { createSemanticHistoryRecord } from './semanticHistoryRecords.js';
9
9
  import { diffNativeSourceImports } from './diffNativeSourceImports.js';
10
10
  import { normalizeNativeDiffImport } from './normalizeNativeDiffImport.js';
11
11
  import { attachBidirectionalMatchPortability, classifyBidirectionalTargetPortability } from './bidirectionalTargetPortability.js';
12
+ import { createRoundtripEvidence, createSemanticMergeAdmissionEvidence, summarizeSourceMapBackprojection } from './bidirectionalTargetRoundtripEvidence.js';
12
13
  import {
13
14
  anchorsFromSourceSidecar,
14
15
  classifyBidirectionalReadiness,
@@ -85,16 +86,54 @@ export function createBidirectionalTargetChangeRecord(input = {}, options = {})
85
86
  ...array(targetPortability.reasonCodes),
86
87
  ...sourceAnchorMatches.flatMap((match) => match.reasonCodes)
87
88
  ]);
88
- const evidence = [createBidirectionalEvidence({
89
+ const evidenceId = input.evidenceId ?? `evidence_${idFragment(id)}_bidirectional_target_change`;
90
+ const sourcePatchBundleId = input.sourcePatchBundleId ?? `semantic_patch_bundle_${idFragment(id)}_source_port`;
91
+ const historyRecordId = input.historyRecordId ?? `semantic_history_${idFragment(id)}_target_change`;
92
+ const sourceMapBackprojection = summarizeSourceMapBackprojection(sourceAnchorMatches);
93
+ const roundtripEvidence = createRoundtripEvidence({
89
94
  id,
90
- input,
95
+ evidenceId,
96
+ sourcePatchBundleId,
97
+ historyRecordId,
98
+ source,
99
+ targetChangeSet,
100
+ sourceAnchorMatches,
101
+ targetPortability,
102
+ readiness,
103
+ reasons,
104
+ sourceMapBackprojection
105
+ });
106
+ const semanticMergeAdmission = createSemanticMergeAdmissionEvidence({
107
+ id,
108
+ evidenceId,
109
+ sourcePatchBundleId,
110
+ historyRecordId,
111
+ targetChangeSet,
112
+ sourceAnchorMatches,
113
+ targetPortability,
114
+ readiness,
115
+ reasons,
116
+ roundtripEvidence
117
+ });
118
+ const bidirectionalEvidence = createBidirectionalEvidence({
119
+ id,
120
+ input: { ...input, evidenceId },
91
121
  source,
92
122
  targetChangeSet,
93
123
  sourceAnchorMatches,
94
124
  targetPortability,
95
125
  readiness,
96
126
  reasons
97
- })];
127
+ });
128
+ const evidence = [{
129
+ ...bidirectionalEvidence,
130
+ metadata: {
131
+ ...bidirectionalEvidence.metadata,
132
+ roundtripEvidenceId: roundtripEvidence.id,
133
+ roundtripEvidence,
134
+ semanticMergeAdmission
135
+ }
136
+ }];
98
137
  const sourceChangedRegions = sourceAnchorMatches.flatMap((match) => sourceRegionsForMatch(match, readiness));
99
138
  const sourcePatchBundle = createSemanticPatchBundleRecord({
100
139
  id: `${id}_source_port_projection`,
@@ -112,22 +151,30 @@ export function createBidirectionalTargetChangeRecord(input = {}, options = {})
112
151
  targetPatchId: targetChangeSet.patch?.id,
113
152
  targetMergeCandidateId: targetChangeSet.mergeCandidate?.id,
114
153
  targetPortability,
115
- sourceMapBackprojection: summarizeSourceMapBackprojection(sourceAnchorMatches)
154
+ sourceMapBackprojection,
155
+ roundtripEvidenceId: roundtripEvidence.id,
156
+ semanticMergeAdmission
116
157
  }
117
158
  }, {
118
- id: input.sourcePatchBundleId ?? `semantic_patch_bundle_${idFragment(id)}_source_port`,
159
+ id: sourcePatchBundleId,
119
160
  patchId: targetChangeSet.patch?.id,
120
161
  mergeCandidateId: targetChangeSet.mergeCandidate?.id,
121
162
  admission: { status: readiness === 'blocked' ? 'blocked' : 'needs-review', readiness },
122
163
  metadata: {
123
164
  source: 'createBidirectionalTargetChangeRecord',
165
+ targetChangeSetId: targetChangeSet.id,
166
+ targetPatchId: targetChangeSet.patch?.id,
167
+ targetMergeCandidateId: targetChangeSet.mergeCandidate?.id,
124
168
  targetPortability,
169
+ sourceMapBackprojection,
170
+ roundtripEvidenceId: roundtripEvidence.id,
171
+ semanticMergeAdmission,
125
172
  autoMergeClaim: false,
126
173
  semanticEquivalenceClaim: false
127
174
  }
128
175
  });
129
176
  const historyRecord = createSemanticHistoryRecord({
130
- id: input.historyRecordId ?? `semantic_history_${idFragment(id)}_target_change`,
177
+ id: historyRecordId,
131
178
  importResult: source,
132
179
  language: source?.language,
133
180
  sourcePath: source?.sourcePath,
@@ -155,7 +202,9 @@ export function createBidirectionalTargetChangeRecord(input = {}, options = {})
155
202
  sourcePatchBundleId: sourcePatchBundle.id,
156
203
  targetChangeSetId: targetChangeSet.id,
157
204
  targetPortability,
158
- sourceMapBackprojection: summarizeSourceMapBackprojection(sourceAnchorMatches),
205
+ sourceMapBackprojection,
206
+ roundtripEvidenceId: roundtripEvidence.id,
207
+ semanticMergeAdmission,
159
208
  autoMergeClaim: false,
160
209
  semanticEquivalenceClaim: false
161
210
  }
@@ -172,6 +221,7 @@ export function createBidirectionalTargetChangeRecord(input = {}, options = {})
172
221
  targetChangeSet,
173
222
  sourceAnchorMatches,
174
223
  targetPortability,
224
+ roundtripEvidence,
175
225
  sourcePatchBundle,
176
226
  historyRecord,
177
227
  evidence,
@@ -185,6 +235,9 @@ export function createBidirectionalTargetChangeRecord(input = {}, options = {})
185
235
  deletedSourceAnchors: sourceAnchorMatches.filter((match) => match.status === 'deleted').length,
186
236
  sourceChangedRegions: sourceChangedRegions.length,
187
237
  sourceMapBackedMatches: sourceAnchorMatches.filter((match) => match.sourceMapLinks.length > 0).length,
238
+ sourceMapLinks: sourceMapBackprojection.sourceMapLinks,
239
+ sourceMapMappingIds: sourceMapBackprojection.sourceMapMappingIds.length,
240
+ lineageResolutions: roundtripEvidence.lineageEvidence.lineageResolutionIds.length,
188
241
  targetPortabilityStatus: targetPortability.status,
189
242
  portableTargetRegions: targetPortability.status === 'portable' ? targetPortability.targetChangedRegions : 0,
190
243
  staleTargetRegions: targetPortability.status === 'stale' ? targetPortability.targetChangedRegions : 0,
@@ -195,21 +248,13 @@ export function createBidirectionalTargetChangeRecord(input = {}, options = {})
195
248
  semanticEquivalenceClaim: false,
196
249
  reviewRequired: true,
197
250
  targetPortability,
251
+ roundtripEvidenceId: roundtripEvidence.id,
252
+ semanticMergeAdmission,
198
253
  ...input.metadata
199
254
  }
200
255
  };
201
256
  }
202
257
 
203
- function summarizeSourceMapBackprojection(matches) {
204
- const links = matches.flatMap((match) => match.sourceMapLinks ?? []);
205
- return {
206
- sourceMapBackedMatches: matches.filter((match) => (match.sourceMapLinks ?? []).length > 0).length,
207
- sourceMapLinks: links.length,
208
- sourceMapIds: uniqueStrings(links.map((link) => link.sourceMapId)),
209
- sourceMapMappingIds: uniqueStrings(links.map((link) => link.sourceMapMappingId))
210
- };
211
- }
212
-
213
258
  function array(value) {
214
259
  return value === undefined || value === null ? [] : Array.isArray(value) ? value : [value];
215
260
  }
@@ -1,4 +1,4 @@
1
- import{idFragment}from'../../native-import-utils.js';import{lightweightDependencyRelations}from'../../lightweight-dependency-relations.js';import{lightweightCoverageLosses,scanNativeDeclarations}from'../../native-region-scanner.js';import{semanticOwnershipRegionForDeclaration}from'../../semantic-import-regions.js';import{createSemanticIndexRecord,hashSemanticValue}from'@shapeshift-labs/frontier-lang-kernel';
1
+ import{idFragment,uniqueRecordsById}from'../../native-import-utils.js';import{lightweightDependencyRelations}from'../../lightweight-dependency-relations.js';import{lightweightCoverageLosses,scanNativeDeclarations}from'../../native-region-scanner.js';import{semanticOwnershipRegionForDeclaration,semanticPatchHintForRegion}from'../../semantic-import-regions.js';import{createSemanticIndexRecord,hashSemanticValue}from'@shapeshift-labs/frontier-lang-kernel';
2
2
  export function createLightweightNativeImport(input) {
3
3
  const parser = input.parser ?? `${input.language}.lightweight-declaration-scan`;
4
4
  const rootId = 'native_root';
@@ -19,11 +19,13 @@ export function createLightweightNativeImport(input) {
19
19
  const relations = [];
20
20
  const facts = [];
21
21
  const mappings = [];
22
+ const ownershipRegions = [];
22
23
  const evidenceId = `evidence_${idFragment(input.sourcePath ?? input.language)}_lightweight_scan`;
23
24
  const dependencies = lightweightDependencyRelations(input, declarations, documentId);
24
25
 
25
26
  for (const declaration of declarations) {
26
27
  const ownershipRegion = semanticOwnershipRegionForDeclaration(input, declaration, documentId);
28
+ ownershipRegions.push(ownershipRegion);
27
29
  nodes[rootId].children.push(declaration.nodeId);
28
30
  nodes[declaration.nodeId] = {
29
31
  id: declaration.nodeId,
@@ -122,6 +124,8 @@ export function createLightweightNativeImport(input) {
122
124
  });
123
125
  }
124
126
  losses.push(...lightweightCoverageLosses(input, declarations, input.sourcePreservation));
127
+ const semanticOwnershipRegions = uniqueRecordsById(ownershipRegions);
128
+ const semanticPatchHints = semanticOwnershipRegions.map((region) => semanticPatchHintForRegion(region, 'needs-review'));
125
129
 
126
130
  const semanticIndex = createSemanticIndexRecord({
127
131
  id: `index_${idFragment(input.sourcePath ?? input.language)}`,
@@ -135,6 +139,8 @@ export function createLightweightNativeImport(input) {
135
139
  occurrences,
136
140
  relations,
137
141
  facts,
142
+ ownershipRegions: semanticOwnershipRegions,
143
+ patchHints: semanticPatchHints,
138
144
  evidence: [{
139
145
  id: evidenceId,
140
146
  kind: 'import',
@@ -162,6 +168,8 @@ export function createLightweightNativeImport(input) {
162
168
  losses,
163
169
  semanticIndex,
164
170
  mappings,
171
+ ownershipRegions: semanticOwnershipRegions,
172
+ patchHints: semanticPatchHints,
165
173
  metadata: {
166
174
  parser,
167
175
  scanKind: 'lightweight-declaration-scan',
@@ -1,4 +1,4 @@
1
- import{idFragment}from'../../native-import-utils.js';import{detectNewlineStyle,scanPreservedSourceDirectives,scanPreservedSourceTokens}from'../../native-region-scanner.js';import{hashSemanticValue}from'@shapeshift-labs/frontier-lang-kernel';
1
+ import{countBy,idFragment,uniqueStrings}from'../../native-import-utils.js';import{detectNewlineStyle,scanPreservedSourceDirectives,scanPreservedSourceTokens}from'../../native-region-scanner.js';import{hashSemanticValue}from'@shapeshift-labs/frontier-lang-kernel';
2
2
  export function createNativeSourcePreservation(options) {
3
3
  if (!options || typeof options.sourceText !== 'string') {
4
4
  throw new Error('createNativeSourcePreservation requires sourceText');
@@ -26,6 +26,16 @@ export function createNativeSourcePreservation(options) {
26
26
  maxDirectives: options.maxDirectives
27
27
  });
28
28
  const directives = directiveScan.directives;
29
+ const triviaByKind = countBy(tokensAndTrivia.trivia.map((entry) => entry.kind ?? 'unknown'));
30
+ const directivesByKind = countBy(directives.map((entry) => entry.kind ?? 'directive'));
31
+ const directiveKinds = uniqueStrings(directives.map((entry) => entry.kind ?? 'directive'));
32
+ const commentSpanIds = tokensAndTrivia.trivia
33
+ .filter((entry) => entry.kind === 'comment')
34
+ .map((entry) => entry.id)
35
+ .filter(Boolean);
36
+ const directiveSpanIds = directives
37
+ .map((entry) => entry.id)
38
+ .filter(Boolean);
29
39
  const newline = detectNewlineStyle(sourceText);
30
40
  return {
31
41
  kind: 'frontier.lang.nativeSourcePreservation',
@@ -48,6 +58,11 @@ export function createNativeSourcePreservation(options) {
48
58
  directives: directives.length,
49
59
  comments: tokensAndTrivia.trivia.filter((entry) => entry.kind === 'comment').length,
50
60
  whitespace: tokensAndTrivia.trivia.filter((entry) => entry.kind === 'whitespace' || entry.kind === 'newline').length,
61
+ triviaByKind,
62
+ directivesByKind,
63
+ directiveKinds,
64
+ commentSpanIds,
65
+ directiveSpanIds,
51
66
  exactSourceAvailable: options.includeSourceText !== false,
52
67
  truncated: tokensAndTrivia.truncated || directiveScan.truncated
53
68
  },