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

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 (134) hide show
  1. package/README.md +13 -0
  2. package/dist/declarations/bidirectional-target-change-source-edit.d.ts +30 -0
  3. package/dist/declarations/bidirectional-target-change.d.ts +10 -0
  4. package/dist/declarations/js-ts-safe-member-merge.d.ts +58 -0
  5. package/dist/declarations/js-ts-safe-merge.d.ts +120 -0
  6. package/dist/declarations/js-ts-semantic-conflict-sidecars.d.ts +235 -0
  7. package/dist/declarations/js-ts-semantic-merge-contracts.d.ts +287 -0
  8. package/dist/declarations/js-ts-semantic-merge.d.ts +4 -0
  9. package/dist/declarations/native-import-losses.d.ts +3 -0
  10. package/dist/declarations/native-project-admission-semantic-evidence.d.ts +34 -0
  11. package/dist/declarations/native-project-admission.d.ts +6 -10
  12. package/dist/declarations/semantic-edit-replay-diagnostics.d.ts +12 -0
  13. package/dist/declarations/semantic-edit-script.d.ts +10 -4
  14. package/dist/declarations/semantic-patch-bundle-index.d.ts +45 -0
  15. package/dist/declarations/semantic-patch-bundle-overlaps.d.ts +1 -0
  16. package/dist/declarations/semantic-patch-bundle.d.ts +6 -4
  17. package/dist/declarations/semantic-sidecar-example.d.ts +18 -0
  18. package/dist/declarations/semantic-transform-identity.d.ts +3 -0
  19. package/dist/declarations/source-preservation.d.ts +72 -0
  20. package/dist/declarations/universal-capability.d.ts +4 -0
  21. package/dist/declarations/universal-conversion-artifacts.d.ts +61 -1
  22. package/dist/declarations/universal-conversion-compact-counts.d.ts +51 -0
  23. package/dist/declarations/universal-conversion-plan.d.ts +6 -1
  24. package/dist/declarations/universal-representation-coverage.d.ts +90 -0
  25. package/dist/index.d.ts +4 -0
  26. package/dist/index.js +3 -0
  27. package/dist/internal/index-impl/bidirectionalExactSourceBackprojection.js +199 -0
  28. package/dist/internal/index-impl/bidirectionalSameLanguageSourceProjection.js +112 -0
  29. package/dist/internal/index-impl/bidirectionalSourceEditProjection.js +319 -0
  30. package/dist/internal/index-impl/bidirectionalSourceEditProjectionArtifacts.js +67 -0
  31. package/dist/internal/index-impl/bidirectionalTargetChangeRecordInternals.js +17 -5
  32. package/dist/internal/index-impl/bidirectionalTargetRoundtripEvidence.js +58 -20
  33. package/dist/internal/index-impl/createBidirectionalTargetChangeRecord.js +60 -7
  34. package/dist/internal/index-impl/createLightweightNativeImport.js +1 -0
  35. package/dist/internal/index-impl/createNativeSourcePreservation.js +28 -2
  36. package/dist/internal/index-impl/createProjectImportAdmissionRecord.js +14 -2
  37. package/dist/internal/index-impl/diffNativeSymbols.js +82 -1
  38. package/dist/internal/index-impl/nativeChangeProjectionSourceMapLinks.js +2 -0
  39. package/dist/internal/index-impl/projectImportAdmissionImportEvidence.js +1 -1
  40. package/dist/internal/index-impl/projectImportAdmissionSemanticWarnings.js +178 -0
  41. package/dist/internal/index-impl/projectImportAdmissionSummaries.js +22 -3
  42. package/dist/internal/index-impl/projectSemanticEditScriptToSource.js +54 -69
  43. package/dist/internal/index-impl/replaySemanticEditLineEndings.js +34 -0
  44. package/dist/internal/index-impl/replaySemanticEditProjection.js +78 -78
  45. package/dist/internal/index-impl/semanticEditBundleAdmission.js +7 -3
  46. package/dist/internal/index-impl/semanticEditBundleIndex.js +47 -1
  47. package/dist/internal/index-impl/semanticEditExplicitSourceReplacement.js +40 -0
  48. package/dist/internal/index-impl/semanticEditImportProjection.js +53 -0
  49. package/dist/internal/index-impl/semanticEditOperationCoverage.js +33 -3
  50. package/dist/internal/index-impl/semanticEditProjectionRecord.js +108 -0
  51. package/dist/internal/index-impl/semanticEditReplayAnchors.js +63 -0
  52. package/dist/internal/index-impl/semanticEditReplayDiagnostics.js +39 -0
  53. package/dist/internal/index-impl/semanticEditReplaySourceReplacement.js +85 -0
  54. package/dist/internal/index-impl/semanticEditScripts.js +4 -0
  55. package/dist/internal/index-impl/semanticEditSourceRanges.js +32 -0
  56. package/dist/internal/index-impl/semanticIndexFromNativeDeclarations.js +1 -0
  57. package/dist/internal/index-impl/semanticPatchBundleAdmission.js +92 -9
  58. package/dist/internal/index-impl/semanticPatchBundleOverlaps.js +33 -16
  59. package/dist/internal/index-impl/semanticPatchBundleRecords.js +16 -0
  60. package/dist/internal/index-impl/semanticPatchBundleSourceRecords.js +2 -0
  61. package/dist/internal/index-impl/semanticSidecarQuality.js +111 -0
  62. package/dist/internal/index-impl/semanticSourceEditDedupe.js +69 -9
  63. package/dist/internal/index-impl/semanticTransformIdentityRecords.js +85 -9
  64. package/dist/js-ts-safe-member-merge-result.js +158 -0
  65. package/dist/js-ts-safe-member-merge.js +202 -0
  66. package/dist/js-ts-safe-merge-analyze.js +279 -0
  67. package/dist/js-ts-safe-merge-constants.js +50 -0
  68. package/dist/js-ts-safe-merge-context.js +118 -0
  69. package/dist/js-ts-safe-merge-ledger-validation.js +92 -0
  70. package/dist/js-ts-safe-merge-ledger.js +85 -0
  71. package/dist/js-ts-safe-merge-parse-declarations.js +210 -0
  72. package/dist/js-ts-safe-merge-parse-statements.js +155 -0
  73. package/dist/js-ts-safe-merge-plan.js +190 -0
  74. package/dist/js-ts-safe-merge.js +175 -0
  75. package/dist/js-ts-semantic-conflict-sidecar-constants.js +77 -0
  76. package/dist/js-ts-semantic-conflict-sidecar-detectors.js +195 -0
  77. package/dist/js-ts-semantic-conflict-sidecar-normalize.js +203 -0
  78. package/dist/js-ts-semantic-conflict-sidecar-utils.js +190 -0
  79. package/dist/js-ts-semantic-conflict-sidecars.js +81 -0
  80. package/dist/js-ts-semantic-merge-contract-helpers.js +128 -0
  81. package/dist/js-ts-semantic-merge-contracts.js +217 -0
  82. package/dist/js-ts-semantic-merge-member-containers.js +100 -0
  83. package/dist/js-ts-semantic-merge-member-keys.js +142 -0
  84. package/dist/js-ts-semantic-merge-member-segments.js +185 -0
  85. package/dist/js-ts-semantic-merge-member-source.js +64 -0
  86. package/dist/js-ts-semantic-merge-member-utils.js +18 -0
  87. package/dist/js-ts-semantic-merge-parse.js +15 -0
  88. package/dist/js-ts-semantic-merge.js +21 -0
  89. package/dist/lightweight-dependency-effects.js +51 -0
  90. package/dist/lightweight-dependency-language.js +12 -1
  91. package/dist/lightweight-dependency-relations.js +14 -27
  92. package/dist/native-region-scanner-core.js +33 -1
  93. package/dist/native-region-scanner-csharp.js +151 -0
  94. package/dist/native-region-scanner-dart.js +91 -0
  95. package/dist/native-region-scanner-dynamic.js +21 -151
  96. package/dist/native-region-scanner-functional.js +40 -13
  97. package/dist/native-region-scanner-java.js +97 -0
  98. package/dist/native-region-scanner-js-class.js +100 -0
  99. package/dist/native-region-scanner-js-helpers.js +28 -86
  100. package/dist/native-region-scanner-js-imports.js +121 -1
  101. package/dist/native-region-scanner-js-nested.js +96 -8
  102. package/dist/native-region-scanner-js-structure.js +27 -0
  103. package/dist/native-region-scanner-js-types.js +99 -0
  104. package/dist/native-region-scanner-js.js +70 -118
  105. package/dist/native-region-scanner-kotlin.js +94 -0
  106. package/dist/native-region-scanner-main.js +15 -181
  107. package/dist/native-region-scanner-php.js +80 -0
  108. package/dist/native-region-scanner-python.js +62 -0
  109. package/dist/native-region-scanner-ruby.js +72 -0
  110. package/dist/native-region-scanner-scala.js +91 -0
  111. package/dist/native-region-scanner-spans.js +74 -0
  112. package/dist/native-region-scanner-swift.js +155 -0
  113. package/dist/native-region-scanner.js +14 -10
  114. package/dist/native-source-ledger-helpers.js +195 -0
  115. package/dist/native-source-ledger.js +306 -0
  116. package/dist/native-source-preservation-scanner.js +4 -0
  117. package/dist/semantic-import-callsite-regions.js +136 -0
  118. package/dist/semantic-import-effect-regions.js +283 -0
  119. package/dist/semantic-import-regions.js +11 -2
  120. package/dist/semantic-import-sidecar-entry.js +16 -2
  121. package/dist/semantic-import-sidecar-types.d.ts +2 -0
  122. package/dist/semantic-sidecar-example.js +68 -0
  123. package/dist/universal-capability-matrix.js +23 -0
  124. package/dist/universal-conversion-artifact-query.js +79 -2
  125. package/dist/universal-conversion-artifact-semantic-edit.js +103 -0
  126. package/dist/universal-conversion-artifact-summary.js +33 -1
  127. package/dist/universal-conversion-artifacts.js +13 -48
  128. package/dist/universal-conversion-plan-scoring.js +21 -1
  129. package/dist/universal-conversion-plan-summary.js +30 -0
  130. package/dist/universal-conversion-plan.js +25 -9
  131. package/dist/universal-conversion-route-metadata.js +96 -0
  132. package/dist/universal-conversion-route-operations.js +7 -0
  133. package/dist/universal-representation-coverage.js +193 -0
  134. package/package.json +1 -1
@@ -2,21 +2,25 @@ import { normalizeSemanticMergeReadiness, uniqueStrings } from '../../native-imp
2
2
 
3
3
  export function createSemanticPatchBundleAdmission(input = {}, context = {}) {
4
4
  const transformAdmission = semanticTransformAdmission(context);
5
- const semanticEditAdmission = context.semanticEditAdmission ?? { status: 'none', action: 'none', readiness: 'needs-review', reasonCodes: [] };
5
+ const semanticEditAdmission = semanticEditAdmissionWithReplayRequirement(
6
+ context.semanticEditAdmission ?? { status: 'none', action: 'none', readiness: 'needs-review', reasonCodes: [] }
7
+ );
6
8
  const evidenceAdmission = autoMergeEvidenceAdmission(context, { transformAdmission, semanticEditAdmission });
7
9
  const fallbackReadiness = fallbackAdmissionReadiness(transformAdmission, semanticEditAdmission, evidenceAdmission, context.readiness);
8
- const inputReadiness = normalizeSemanticMergeReadiness(input.readiness ?? fallbackReadiness) ?? input.readiness ?? fallbackReadiness;
9
- const readiness = hasPositiveApplyAction(transformAdmission, semanticEditAdmission) && evidenceAdmission.action !== 'admit'
10
+ const requestedReadiness = normalizeSemanticMergeReadiness(input.readiness) ?? input.readiness;
11
+ const inputReadiness = fallbackReadiness === 'blocked' ? 'blocked' : requestedReadiness ?? fallbackReadiness;
12
+ const positiveApply = !hasSkipReadyAction(semanticEditAdmission) && hasPositiveApplyAction(transformAdmission, semanticEditAdmission);
13
+ const readiness = positiveApply && evidenceAdmission.action !== 'admit'
10
14
  ? evidenceAdmission.readiness
11
15
  : inputReadiness;
12
16
  const computedStatus = admissionStatusForReadiness(readiness, transformAdmission, semanticEditAdmission, evidenceAdmission);
13
- const status = input.status === 'admitted' && computedStatus !== 'admitted' ? computedStatus : input.status ?? computedStatus;
17
+ const status = safePatchBundleStatus(input.status, computedStatus);
14
18
  const computedAutoApplyCandidate = status === 'admitted' &&
15
- hasPositiveApplyAction(transformAdmission, semanticEditAdmission) &&
19
+ positiveApply &&
16
20
  evidenceAdmission.action === 'admit';
17
21
  const autoApplyCandidate = input.autoApplyCandidate === true ? computedAutoApplyCandidate : input.autoApplyCandidate ?? computedAutoApplyCandidate;
18
22
  const admittedWithoutPositiveProof = status === 'admitted' &&
19
- hasPositiveApplyAction(transformAdmission, semanticEditAdmission) &&
23
+ positiveApply &&
20
24
  evidenceAdmission.action !== 'admit';
21
25
  return compactRecord({
22
26
  status,
@@ -35,7 +39,7 @@ export function createSemanticPatchBundleAdmission(input = {}, context = {}) {
35
39
  ...strings(semanticEditAdmission.reasonCodes),
36
40
  ...strings(evidenceAdmission.reasonCodes)
37
41
  ].filter(Boolean)),
38
- conflictKeys: uniqueStrings([...strings(input.conflictKeys), ...context.conflictKeys]),
42
+ conflictKeys: uniqueStrings([...strings(input.conflictKeys), ...strings(context.conflictKeys)]),
39
43
  admittedAt: input.admittedAt,
40
44
  reviewerId: input.reviewerId,
41
45
  evidenceIds: uniqueStrings([...strings(input.evidenceIds), ...strings(transformAdmission.evidenceIds), ...strings(evidenceAdmission.evidenceIds)]),
@@ -70,10 +74,15 @@ function semanticTransformAdmission(context) {
70
74
  transformKeys: strings(index.semanticTransformKeys),
71
75
  contentHashes: strings(index.semanticTransformContentHashes),
72
76
  projectionIdentityHashes: strings(index.projectionIdentityHashes),
77
+ baseHashes: strings(index.transformBaseHashes),
78
+ targetHashes: strings(index.transformTargetHashes),
73
79
  sourceLanguages: strings(index.transformSourceLanguages),
74
80
  targetLanguages: strings(index.transformTargetLanguages),
75
81
  sourcePaths: strings(index.transformSourcePaths),
76
82
  targetPaths: strings(index.transformTargetPaths),
83
+ sourceMapIds: strings(index.transformSourceMapIds),
84
+ sourceMapLinkIds: strings(index.transformSourceMapLinkIds),
85
+ sourceMapMappingIds: strings(index.transformSourceMapMappingIds),
77
86
  evidenceIds: strings(index.semanticTransformEvidenceIds)
78
87
  });
79
88
  }
@@ -106,8 +115,12 @@ function autoMergeEvidenceAdmission(context, admissions) {
106
115
  ...array(context.source?.semanticPatch?.evidence),
107
116
  ...array(context.mergeCandidate?.evidence)
108
117
  ]);
109
- const positiveApply = hasPositiveApplyAttempt(admissions.transformAdmission, admissions.semanticEditAdmission);
110
- if (!positiveApply) return { status: 'none', action: 'none', readiness: 'needs-review', reasonCodes: [], evidenceIds: evidenceIds(evidence) };
118
+ const skipReady = hasSkipReadyAction(admissions.semanticEditAdmission);
119
+ const positiveApply = !skipReady &&
120
+ hasPositiveApplyAttempt(admissions.transformAdmission, admissions.semanticEditAdmission);
121
+ if (!positiveApply) return skipReady
122
+ ? skipEvidenceAdmission(evidence)
123
+ : { status: 'none', action: 'none', readiness: 'needs-review', reasonCodes: [], evidenceIds: evidenceIds(evidence) };
111
124
  const summary = summarizeAutoMergeEvidence(evidence);
112
125
  const blocked = summary.failed > 0 || summary.conflict > 0;
113
126
  const ready = !blocked && summary.stale === 0 && summary.passed > 0;
@@ -125,6 +138,23 @@ function autoMergeEvidenceAdmission(context, admissions) {
125
138
  });
126
139
  }
127
140
 
141
+ function skipEvidenceAdmission(evidence) {
142
+ const summary = summarizeAutoMergeEvidence(evidence);
143
+ const blocked = summary.failed > 0 || summary.conflict > 0;
144
+ const status = blocked ? 'blocked' : summary.stale > 0 ? 'stale' : summary.passed > 0 ? 'ready' : 'none';
145
+ return compactRecord({
146
+ status,
147
+ action: blocked ? 'block' : status === 'stale' ? 'rerun-semantic-import' : status === 'ready' ? 'skip' : 'none',
148
+ readiness: blocked ? 'blocked' : status === 'ready' ? 'ready' : 'needs-review',
149
+ reasonCodes: status === 'none' ? [] : autoMergeEvidenceReasonCodes(summary, status),
150
+ evidenceIds: summary.evidenceIds,
151
+ passed: summary.passed,
152
+ failed: summary.failed,
153
+ conflict: summary.conflict,
154
+ stale: summary.stale
155
+ });
156
+ }
157
+
128
158
  function summarizeAutoMergeEvidence(evidence) {
129
159
  const testLike = evidence.filter(isAutoMergeTestEvidence);
130
160
  const failed = testLike.filter((record) => evidenceStatus(record, ['failed', 'failure', 'error', 'blocked', 'rejected']));
@@ -155,6 +185,7 @@ function fallbackAdmissionReadiness(transformAdmission, semanticEditAdmission, e
155
185
  if ([transformAdmission.readiness, semanticEditAdmission.readiness, evidenceAdmission.readiness].includes('blocked')) return 'blocked';
156
186
  if (hasSkipReadyAction(semanticEditAdmission)) return 'ready';
157
187
  if (hasPositiveApplyAction(transformAdmission, semanticEditAdmission)) return evidenceAdmission.action === 'admit' ? 'ready' : evidenceAdmission.readiness;
188
+ if (semanticEditAdmission.action === 'review' || semanticEditAdmission.status === 'needs-review') return 'needs-review';
158
189
  return fallback;
159
190
  }
160
191
 
@@ -164,6 +195,12 @@ function admissionStatusForReadiness(readiness, transformAdmission, semanticEdit
164
195
  return readiness === 'needs-review' ? 'needs-review' : 'proposed';
165
196
  }
166
197
 
198
+ function safePatchBundleStatus(requested, computed) {
199
+ if (computed === 'blocked' && requested !== 'rejected') return 'blocked';
200
+ if (requested === 'admitted' && computed !== 'admitted') return computed;
201
+ return requested ?? computed;
202
+ }
203
+
167
204
  function hasAdmissibleReadyAction(transformAdmission, semanticEditAdmission, evidenceAdmission) {
168
205
  return hasSkipReadyAction(semanticEditAdmission) ||
169
206
  (hasPositiveApplyAction(transformAdmission, semanticEditAdmission) && evidenceAdmission.action === 'admit');
@@ -183,6 +220,51 @@ function hasSkipReadyAction(semanticEditAdmission) {
183
220
  return semanticEditAdmission.action === 'skip' && semanticEditAdmission.readiness === 'ready' && semanticEditAdmission.reviewRequired === false;
184
221
  }
185
222
 
223
+ function semanticEditAdmissionWithReplayRequirement(admission) {
224
+ if (!requiresSemanticEditReplay(admission) || hasAcceptedCleanSemanticEditReplay(admission)) return admission;
225
+ return compactRecord({
226
+ ...admission,
227
+ status: 'needs-review',
228
+ action: 'review',
229
+ readiness: 'needs-review',
230
+ reviewRequired: true,
231
+ autoApplyCandidate: false,
232
+ reasonCodes: uniqueStrings([
233
+ ...strings(admission.reasonCodes).filter((reason) => reason !== 'semantic-edit-positive-auto-merge-proof'),
234
+ ...semanticEditReplayRequirementReasonCodes(admission)
235
+ ])
236
+ });
237
+ }
238
+
239
+ function requiresSemanticEditReplay(admission) {
240
+ return admission.action === 'admit' ||
241
+ admission.autoApplyCandidate === true ||
242
+ admission.status === 'ready' ||
243
+ strings(admission.reasonCodes).includes('semantic-edit-positive-auto-merge-proof');
244
+ }
245
+
246
+ function hasAcceptedCleanSemanticEditReplay(admission) {
247
+ const summary = admission.summary ?? {};
248
+ const acceptedClean = count(summary.acceptedClean);
249
+ const alreadyApplied = count(summary.alreadyApplied);
250
+ const replays = count(summary.replays);
251
+ return acceptedClean > 0 && replays > 0 && acceptedClean + alreadyApplied === replays;
252
+ }
253
+
254
+ function semanticEditReplayRequirementReasonCodes(admission) {
255
+ const summary = admission.summary ?? {};
256
+ const scripts = count(summary.scripts);
257
+ const projections = count(summary.projections);
258
+ const replays = count(summary.replays);
259
+ const acceptedClean = count(summary.acceptedClean);
260
+ return [
261
+ scripts > 0 && projections === 0 ? 'semantic-edit-projection-missing' : undefined,
262
+ (scripts > 0 || projections > 0) && replays === 0 ? 'semantic-edit-replay-missing' : undefined,
263
+ replays > 0 && acceptedClean === 0 ? 'semantic-edit-replay-accepted-clean-missing' : undefined,
264
+ 'semantic-edit-replay-required'
265
+ ].filter(Boolean);
266
+ }
267
+
186
268
  function hasCrossLanguageTransform(index) {
187
269
  const source = new Set(strings(index.transformSourceLanguages));
188
270
  return strings(index.transformTargetLanguages).some((target) => !source.has(target));
@@ -211,6 +293,7 @@ function uniqueEvidenceRecords(records) {
211
293
  }
212
294
 
213
295
  function evidenceIds(evidence) { return uniqueStrings(evidence.map((record) => record.id)); }
296
+ function count(value) { const number = Number(value ?? 0); return Number.isFinite(number) ? number : 0; }
214
297
  function array(value) { if (value === undefined || value === null) return []; return Array.isArray(value) ? value : [value]; }
215
298
  function strings(value) { return array(value).map((entry) => String(entry ?? '')).filter(Boolean); }
216
299
  function compactRecord(value) { return Object.fromEntries(Object.entries(value ?? {}).filter(([, entry]) => entry !== undefined && (!Array.isArray(entry) || entry.length > 0))); }
@@ -65,7 +65,8 @@ export function compareSemanticPatchBundleRecords(left={},right={},options={}){
65
65
  semanticSignals:shared.semanticEditKeys.length+shared.semanticIdentityHashes.length+shared.sourceIdentityHashes.length+shared.semanticTransformIdentityHashes.length+shared.projectionIdentityHashes.length,
66
66
  sourceSignals:shared.regionKeys.length+shared.conflictKeys.length+shared.sourcePaths.length+shared.semanticEditReplayCurrentHashes.length,
67
67
  baseHashMismatch:admission.reasonCodes.includes('base-hash-mismatch'),
68
- targetHashMismatch:admission.reasonCodes.includes('target-hash-mismatch')
68
+ targetHashMismatch:admission.reasonCodes.includes('target-hash-mismatch'),
69
+ replayOutputHashMismatch:admission.reasonCodes.includes('replay-output-hash-mismatch')
69
70
  },
70
71
  metadata:compactRecord(options.metadata)
71
72
  };
@@ -110,21 +111,32 @@ function sharedIndex(left,right,options){
110
111
  baseHashes:intersect(left.baseHashes,right.baseHashes),
111
112
  targetHashes:intersect(left.targetHashes,right.targetHashes)
112
113
  };
113
- const scopedEdit=hasSharedEditScope(shared);
114
- const scopedSource=hasSharedSourceScope(shared);
115
- return{
114
+ const semanticKeyIndependent=hasDisjointSemanticEditScope(left,right,shared);
115
+ const scopedShared={
116
116
  ...shared,
117
- operationContentHashes:scopedEdit?shared.operationContentHashes:[],
118
- editContentHashes:scopedEdit?shared.editContentHashes:[],
119
- semanticEditKeys:scopedSource?shared.semanticEditKeys:[],
120
- semanticIdentityHashes:scopedSource?shared.semanticIdentityHashes:[],
121
- semanticEditReplayCurrentHashes:scopedSource?shared.semanticEditReplayCurrentHashes:[],
122
- semanticEditReplayOutputHashes:scopedEdit?shared.semanticEditReplayOutputHashes:[],
123
- semanticTransformContentHashes:shared.projectionIdentityHashes.length?shared.semanticTransformContentHashes:[],
124
- semanticTransformIdentityHashes:shared.projectionIdentityHashes.length?shared.semanticTransformIdentityHashes:[]
117
+ sourcePaths:semanticKeyIndependent?[]:shared.sourcePaths
118
+ };
119
+ const scopedEdit=hasSharedEditScope(scopedShared);
120
+ const scopedSource=hasSharedSourceScope(scopedShared);
121
+ return{
122
+ ...scopedShared,
123
+ operationContentHashes:scopedEdit?scopedShared.operationContentHashes:[],
124
+ editContentHashes:scopedEdit?scopedShared.editContentHashes:[],
125
+ semanticEditKeys:scopedSource?scopedShared.semanticEditKeys:[],
126
+ semanticIdentityHashes:scopedSource?scopedShared.semanticIdentityHashes:[],
127
+ semanticEditReplayCurrentHashes:scopedSource?scopedShared.semanticEditReplayCurrentHashes:[],
128
+ semanticEditReplayOutputHashes:scopedEdit?scopedShared.semanticEditReplayOutputHashes:[],
129
+ semanticTransformContentHashes:scopedShared.projectionIdentityHashes.length?scopedShared.semanticTransformContentHashes:[],
130
+ semanticTransformIdentityHashes:scopedShared.projectionIdentityHashes.length?scopedShared.semanticTransformIdentityHashes:[]
125
131
  };
126
132
  }
127
133
 
134
+ function hasDisjointSemanticEditScope(left,right,shared){
135
+ return Boolean(shared.sourcePaths.length&&left.semanticEditKeys.length&&right.semanticEditKeys.length
136
+ &&shared.semanticEditKeys.length===0&&shared.regionKeys.length===0&&shared.conflictKeys.length===0
137
+ &&shared.semanticIdentityHashes.length===0&&shared.sourceIdentityHashes.length===0);
138
+ }
139
+
128
140
  function hasSharedEditScope(shared){
129
141
  return Boolean(shared.regionKeys.length||shared.conflictKeys.length||shared.sourceIdentityHashes.length
130
142
  ||(shared.sourcePaths.length&&(shared.semanticEditKeys.length||shared.semanticIdentityHashes.length)));
@@ -135,7 +147,10 @@ function hasSharedSourceScope(shared){
135
147
  }
136
148
 
137
149
  function overlapAdmission(shared,{leftIndex,rightIndex,options}){
138
- const hashMismatch=disjointNonEmpty(leftIndex.baseHashes,rightIndex.baseHashes)||disjointNonEmpty(leftIndex.targetHashes,rightIndex.targetHashes);
150
+ const baseHashMismatch=disjointNonEmpty(leftIndex.baseHashes,rightIndex.baseHashes);
151
+ const targetHashMismatch=disjointNonEmpty(leftIndex.targetHashes,rightIndex.targetHashes);
152
+ const replayOutputHashMismatch=disjointNonEmpty(leftIndex.semanticEditReplayOutputHashes,rightIndex.semanticEditReplayOutputHashes);
153
+ const hashMismatch=baseHashMismatch||targetHashMismatch||replayOutputHashMismatch;
139
154
  const sourceRelated=shared.sourcePaths.length||shared.regionKeys.length||shared.conflictKeys.length||shared.sourceIdentityHashes.length;
140
155
  const editContent=shared.operationContentHashes.length||shared.editContentHashes.length||shared.semanticEditReplayOutputHashes.length;
141
156
  const transformContent=shared.semanticTransformContentHashes.length&&shared.projectionIdentityHashes.length;
@@ -158,8 +173,9 @@ function overlapAdmission(shared,{leftIndex,rightIndex,options}){
158
173
  shared.regionKeys.length?'same-region-key':undefined,
159
174
  shared.conflictKeys.length?'same-conflict-key':undefined,
160
175
  shared.sourcePaths.length?'same-source-path':undefined,
161
- status!=='independent'&&disjointNonEmpty(leftIndex.baseHashes,rightIndex.baseHashes)?'base-hash-mismatch':undefined,
162
- status!=='independent'&&disjointNonEmpty(leftIndex.targetHashes,rightIndex.targetHashes)?'target-hash-mismatch':undefined
176
+ status!=='independent'&&baseHashMismatch?'base-hash-mismatch':undefined,
177
+ status!=='independent'&&targetHashMismatch?'target-hash-mismatch':undefined,
178
+ status!=='independent'&&replayOutputHashMismatch?'replay-output-hash-mismatch':undefined
163
179
  ]);
164
180
  return{
165
181
  status,
@@ -223,7 +239,8 @@ function matchesOverlap(overlap,query){
223
239
  function overlapScore(status,shared,reasonCodes){
224
240
  const base=status==='duplicate'?100:status==='semantic-overlap'?75:status==='source-overlap'?35:0;
225
241
  const sharedBonus=Math.min(20,countShared(shared));
226
- const stalePenalty=reasonCodes.includes('base-hash-mismatch')||reasonCodes.includes('target-hash-mismatch')?15:0;
242
+ const stalePenalty=reasonCodes.includes('base-hash-mismatch')||reasonCodes.includes('target-hash-mismatch')
243
+ ||reasonCodes.includes('replay-output-hash-mismatch')?15:0;
227
244
  return Math.max(0,base+sharedBonus-stalePenalty);
228
245
  }
229
246
 
@@ -141,11 +141,13 @@ function recordIndex(parts){
141
141
  semanticEditReplayIds:editIndex.semanticEditReplayIds,
142
142
  semanticEditReplayStatuses:editIndex.semanticEditReplayStatuses,
143
143
  semanticEditReplayActions:editIndex.semanticEditReplayActions,
144
+ semanticEditReplayReasonCodes:editIndex.semanticEditReplayReasonCodes,
144
145
  semanticEditAdmissionStatuses:uniqueStrings([editAdmission.status]),
145
146
  semanticEditAdmissionActions:uniqueStrings([editAdmission.action]),
146
147
  semanticEditAdmissionReadinesses:uniqueStrings([editAdmission.readiness]),
147
148
  semanticEditReplayCurrentHashes:editIndex.semanticEditReplayCurrentHashes,
148
149
  semanticEditReplayOutputHashes:editIndex.semanticEditReplayOutputHashes,
150
+ sourceBackprojectionModes:editIndex.sourceBackprojectionModes,
149
151
  semanticEditKeys:editIndex.semanticEditKeys,
150
152
  semanticIdentityHashes:editIndex.semanticIdentityHashes,
151
153
  sourceIdentityHashes:editIndex.sourceIdentityHashes,
@@ -156,12 +158,18 @@ function recordIndex(parts){
156
158
  semanticTransformIdentityHashes:semanticTransformIndex.semanticTransformIdentityHashes,
157
159
  semanticTransformContentHashes:semanticTransformIndex.semanticTransformContentHashes,
158
160
  projectionIdentityHashes:semanticTransformIndex.projectionIdentityHashes,
161
+ transformBaseHashes:semanticTransformIndex.transformBaseHashes,
162
+ transformTargetHashes:semanticTransformIndex.transformTargetHashes,
159
163
  semanticTransformReadinesses:semanticTransformIndex.semanticTransformReadinesses,
160
164
  semanticTransformEvidenceIds:semanticTransformIndex.semanticTransformEvidenceIds,
161
165
  transformSourceLanguages:semanticTransformIndex.transformSourceLanguages,
162
166
  transformTargetLanguages:semanticTransformIndex.transformTargetLanguages,
163
167
  transformSourcePaths:semanticTransformIndex.transformSourcePaths,
164
168
  transformTargetPaths:semanticTransformIndex.transformTargetPaths,
169
+ transformCrossLanguages:semanticTransformIndex.transformCrossLanguages,
170
+ transformSourceMapIds:semanticTransformIndex.transformSourceMapIds,
171
+ transformSourceMapLinkIds:semanticTransformIndex.transformSourceMapLinkIds,
172
+ transformSourceMapMappingIds:semanticTransformIndex.transformSourceMapMappingIds,
165
173
  targetPortabilityStatuses:uniqueStrings([parts.targetPortability?.status]),
166
174
  targetPortabilityActions:uniqueStrings([parts.targetPortability?.action]),
167
175
  targetPortabilityReasonCodes:uniqueStrings(parts.targetPortability?.reasonCodes),
@@ -202,11 +210,13 @@ function matchesRecord(record,query){
202
210
  &&matchAny(queryValues(query.semanticEditReplayId,query.semanticEditReplayIds),index.semanticEditReplayIds)
203
211
  &&matchAny(queryValues(query.semanticEditReplayStatus,query.semanticEditReplayStatuses),index.semanticEditReplayStatuses)
204
212
  &&matchAny(queryValues(query.semanticEditReplayAction,query.semanticEditReplayActions),index.semanticEditReplayActions)
213
+ &&matchAny(queryValues(query.semanticEditReplayReasonCode,query.semanticEditReplayReasonCodes),index.semanticEditReplayReasonCodes)
205
214
  &&matchAny(queryValues(query.semanticEditAdmissionStatus,query.semanticEditAdmissionStatuses),index.semanticEditAdmissionStatuses)
206
215
  &&matchAny(queryValues(query.semanticEditAdmissionAction,query.semanticEditAdmissionActions),index.semanticEditAdmissionActions)
207
216
  &&matchAny(queryValues(query.semanticEditAdmissionReadiness,query.semanticEditAdmissionReadinesses),index.semanticEditAdmissionReadinesses)
208
217
  &&matchAny(queryValues(query.semanticEditReplayCurrentHash,query.semanticEditReplayCurrentHashes),index.semanticEditReplayCurrentHashes)
209
218
  &&matchAny(queryValues(query.semanticEditReplayOutputHash,query.semanticEditReplayOutputHashes),index.semanticEditReplayOutputHashes)
219
+ &&matchAny(queryValues(query.sourceBackprojectionMode,query.sourceBackprojectionModes),index.sourceBackprojectionModes)
210
220
  &&matchAny(queryValues(query.semanticEditKey,query.semanticEditKeys),index.semanticEditKeys)
211
221
  &&matchAny(queryValues(query.semanticIdentityHash,query.semanticIdentityHashes),index.semanticIdentityHashes)
212
222
  &&matchAny(queryValues(query.sourceIdentityHash,query.sourceIdentityHashes),index.sourceIdentityHashes)
@@ -217,12 +227,18 @@ function matchesRecord(record,query){
217
227
  &&matchAny(queryValues(query.semanticTransformIdentityHash,query.semanticTransformIdentityHashes),index.semanticTransformIdentityHashes)
218
228
  &&matchAny(queryValues(query.semanticTransformContentHash,query.semanticTransformContentHashes),index.semanticTransformContentHashes)
219
229
  &&matchAny(queryValues(query.projectionIdentityHash,query.projectionIdentityHashes),index.projectionIdentityHashes)
230
+ &&matchAny(queryValues(query.transformBaseHash,query.transformBaseHashes),index.transformBaseHashes)
231
+ &&matchAny(queryValues(query.transformTargetHash,query.transformTargetHashes),index.transformTargetHashes)
220
232
  &&matchAny(queryValues(query.semanticTransformReadiness,query.semanticTransformReadinesses),index.semanticTransformReadinesses)
221
233
  &&matchAny(queryValues(query.semanticTransformEvidenceId,query.semanticTransformEvidenceIds),index.semanticTransformEvidenceIds)
222
234
  &&matchAny(queryValues(query.transformSourceLanguage,query.transformSourceLanguages),index.transformSourceLanguages)
223
235
  &&matchAny(queryValues(query.transformTargetLanguage,query.transformTargetLanguages),index.transformTargetLanguages)
224
236
  &&matchAny(queryValues(query.transformSourcePath,query.transformSourcePaths),index.transformSourcePaths)
225
237
  &&matchAny(queryValues(query.transformTargetPath,query.transformTargetPaths),index.transformTargetPaths)
238
+ &&matchAny(queryValues(query.transformCrossLanguage,query.transformCrossLanguages),index.transformCrossLanguages)
239
+ &&matchAny(queryValues(query.transformSourceMapId,query.transformSourceMapIds),index.transformSourceMapIds)
240
+ &&matchAny(queryValues(query.transformSourceMapLinkId,query.transformSourceMapLinkIds),index.transformSourceMapLinkIds)
241
+ &&matchAny(queryValues(query.transformSourceMapMappingId,query.transformSourceMapMappingIds),index.transformSourceMapMappingIds)
226
242
  &&matchAny(queryValues(query.targetPortabilityStatus,query.targetPortabilityStatuses),index.targetPortabilityStatuses)
227
243
  &&matchAny(queryValues(query.targetPortabilityAction,query.targetPortabilityActions),index.targetPortabilityActions)
228
244
  &&matchAny(queryValues(query.targetPortabilityReasonCode,query.targetPortabilityReasonCodes),index.targetPortabilityReasonCodes)
@@ -102,6 +102,8 @@ export function normalizeSourceMapLinks(links) {
102
102
  precision: link.precision,
103
103
  sourceSpan: link.sourceSpan,
104
104
  generatedSpan: link.generatedSpan,
105
+ sourceReplacementText: link.sourceReplacementText,
106
+ sourceReplacementTextHash: link.sourceReplacementTextHash,
105
107
  regionKey: link.ownershipRegionKey,
106
108
  regionKind: link.ownershipRegionKind
107
109
  }));
@@ -0,0 +1,111 @@
1
+ import { uniqueStrings } from '../../native-import-utils.js';
2
+
3
+ function summarizeSemanticSidecarQuality(sources) {
4
+ const records = uniqueSemanticSidecarQualityRecords(array(sources).flatMap(semanticSidecarQualityRecords));
5
+ const warningCodes = uniqueStrings(records.flatMap(sidecarQualityWarningCodes));
6
+ const zeroRecordWarningCodes = uniqueStrings(records.flatMap(sidecarQualityZeroRecordWarningCodes));
7
+ return {
8
+ records: records.length,
9
+ symbols: records.reduce((sum, record) => sum + sidecarQualityCount(record, 'symbolCount', 'symbols'), 0),
10
+ ownershipRegions: records.reduce((sum, record) => sum + sidecarQualityCount(record, 'ownershipRegionCount', 'ownershipRegions'), 0),
11
+ patchHints: records.reduce((sum, record) => sum + sidecarQualityCount(record, 'patchHintCount', 'patchHints'), 0),
12
+ warnings: records.reduce((sum, record) => sum + sidecarQualityWarningCount(record), 0),
13
+ zeroRecordWarnings: zeroRecordWarningCodes.length,
14
+ warningCodes,
15
+ zeroRecordWarningCodes
16
+ };
17
+ }
18
+
19
+ function semanticSidecarQualityRecords(source) {
20
+ if (!source || typeof source !== 'object') return [];
21
+ return [
22
+ source.semanticSidecarQuality,
23
+ source.sidecarQuality,
24
+ source.semanticSidecar?.quality,
25
+ source.sidecar?.quality,
26
+ source.semanticSidecarAdmission,
27
+ source.sidecarAdmission,
28
+ source.semanticSidecar?.admission,
29
+ source.sidecar?.admission,
30
+ source.metadata?.semanticSidecarQuality,
31
+ source.metadata?.sidecarQuality,
32
+ source.metadata?.semanticSidecarAdmission,
33
+ source.metadata?.sidecarAdmission
34
+ ].filter(looksLikeSemanticSidecarQuality);
35
+ }
36
+
37
+ function looksLikeSemanticSidecarQuality(value) {
38
+ return value && typeof value === 'object' && (
39
+ value.schema === 'frontier.lang.semanticSidecarQuality.v1' ||
40
+ value.schema === 'frontier.lang.semanticSidecarAdmission.v1' ||
41
+ value.imported !== undefined ||
42
+ value.eligible !== undefined ||
43
+ value.expectedSatisfied !== undefined ||
44
+ value.warningCount !== undefined ||
45
+ value.emptyEvidenceWarnings !== undefined ||
46
+ value.proofSummary !== undefined ||
47
+ value.counts !== undefined
48
+ );
49
+ }
50
+
51
+ function uniqueSemanticSidecarQualityRecords(records) {
52
+ const seen = new Set();
53
+ const result = [];
54
+ for (const record of records) {
55
+ const key = record.id ?? JSON.stringify({
56
+ schema: record.schema,
57
+ symbols: sidecarQualityCount(record, 'symbolCount', 'symbols'),
58
+ ownershipRegions: sidecarQualityCount(record, 'ownershipRegionCount', 'ownershipRegions'),
59
+ patchHints: sidecarQualityCount(record, 'patchHintCount', 'patchHints'),
60
+ warningCodes: sidecarQualityWarningCodes(record)
61
+ });
62
+ if (seen.has(key)) continue;
63
+ seen.add(key);
64
+ result.push(record);
65
+ }
66
+ return result;
67
+ }
68
+
69
+ function sidecarQualityCount(record, field, countsField) {
70
+ for (const value of [record?.[field], record?.counts?.[countsField]]) {
71
+ const count = Number(value ?? 0);
72
+ if (Number.isFinite(count) && count > 0) return count;
73
+ }
74
+ return 0;
75
+ }
76
+
77
+ function sidecarQualityWarningCount(record) {
78
+ const count = Number(record?.warningCount ?? 0);
79
+ if (Number.isFinite(count) && count > 0) return count;
80
+ return sidecarQualityWarningCodes(record).length;
81
+ }
82
+
83
+ function sidecarQualityWarningCodes(record) {
84
+ return uniqueStrings([
85
+ ...array(record?.warnings).map((warning) => warning?.code ?? warning?.reasonCode),
86
+ ...array(record?.emptyEvidenceWarnings).map((warning) => warning?.code ?? warning?.reasonCode),
87
+ ...strings(record?.expectedMissingReasonCodes),
88
+ ...strings(record?.reasonCodes)
89
+ ].filter(Boolean));
90
+ }
91
+
92
+ function sidecarQualityZeroRecordWarningCodes(record) {
93
+ return sidecarQualityWarningCodes(record).filter(isZeroRecordWarningCode);
94
+ }
95
+
96
+ function isZeroRecordWarningCode(code) {
97
+ return [
98
+ 'empty-evidence',
99
+ 'empty-semantic-index',
100
+ 'expected-semantic-import-empty',
101
+ 'expected-semantic-import-missing',
102
+ 'missing-imports',
103
+ 'missing-ownership-regions',
104
+ 'missing-patch-hints'
105
+ ].includes(code);
106
+ }
107
+
108
+ function array(value) { if (value === undefined || value === null) return []; return Array.isArray(value) ? value : [value]; }
109
+ function strings(value) { return array(value).map((entry) => String(entry ?? '')).filter(Boolean); }
110
+
111
+ export { summarizeSemanticSidecarQuality };
@@ -8,11 +8,18 @@ export function applySourceEdits(sourceText, edits) {
8
8
  }
9
9
 
10
10
  export function dedupeSourceEdits(edits) {
11
- const exact = dedupeExactInsertions(edits);
12
- const covered = removeCoveredContainerReplacements(exact.edits);
11
+ const exact = dedupeExactEdits(edits);
12
+ const noops = removeNoopReplacements(exact.edits);
13
+ const coveredDeletes = removeContainedDeletionEdits(noops.edits);
14
+ const covered = removeCoveredContainerReplacements(coveredDeletes.edits);
13
15
  return {
14
16
  edits: covered.edits,
15
- skippedOperationIds: [...exact.skippedOperationIds, ...covered.skippedOperationIds]
17
+ skippedOperationIds: [
18
+ ...exact.skippedOperationIds,
19
+ ...noops.skippedOperationIds,
20
+ ...coveredDeletes.skippedOperationIds,
21
+ ...covered.skippedOperationIds
22
+ ]
16
23
  };
17
24
  }
18
25
 
@@ -27,7 +34,7 @@ export function validateSourceEdits(edits) {
27
34
  return uniqueStrings(reasons);
28
35
  }
29
36
 
30
- function dedupeExactInsertions(edits) {
37
+ function dedupeExactEdits(edits) {
31
38
  const seen = new Map();
32
39
  const result = [];
33
40
  const skippedOperationIds = [];
@@ -43,6 +50,19 @@ function dedupeExactInsertions(edits) {
43
50
  return { edits: result, skippedOperationIds };
44
51
  }
45
52
 
53
+ function removeNoopReplacements(edits) {
54
+ const skippedOperationIds = [];
55
+ const result = [];
56
+ for (const edit of edits) {
57
+ if (edit.editKind === 'replace' && !edit.alreadyApplied && edit.current === edit.replacement) {
58
+ skippedOperationIds.push(edit.operationId);
59
+ continue;
60
+ }
61
+ result.push(edit);
62
+ }
63
+ return { edits: result, skippedOperationIds };
64
+ }
65
+
46
66
  function removeCoveredContainerReplacements(edits) {
47
67
  const skippedOperationIds = [];
48
68
  const result = [];
@@ -56,6 +76,31 @@ function removeCoveredContainerReplacements(edits) {
56
76
  return { edits: result, skippedOperationIds };
57
77
  }
58
78
 
79
+ function removeContainedDeletionEdits(edits) {
80
+ const skippedOperationIds = [];
81
+ const result = [];
82
+ for (const edit of edits) {
83
+ if (deleteCoveredByLargerDelete(edit, edits)) {
84
+ skippedOperationIds.push(edit.operationId);
85
+ continue;
86
+ }
87
+ result.push(edit);
88
+ }
89
+ return { edits: result, skippedOperationIds };
90
+ }
91
+
92
+ function deleteCoveredByLargerDelete(edit, edits) {
93
+ return edit.editKind === 'delete' && !edit.alreadyApplied && edits.some((candidate) => (
94
+ candidate !== edit &&
95
+ candidate.editKind === 'delete' &&
96
+ !candidate.alreadyApplied &&
97
+ sameSourcePath(candidate, edit) &&
98
+ candidate.start <= edit.start &&
99
+ edit.end <= candidate.end &&
100
+ (candidate.start !== edit.start || candidate.end !== edit.end)
101
+ ));
102
+ }
103
+
59
104
  function containerReplacementCoveredByInsertions(edit, edits) {
60
105
  if (edit.editKind !== 'replace' || edit.alreadyApplied) return false;
61
106
  const insertions = containedInsertions(edit, edits);
@@ -76,15 +121,30 @@ function containedInsertions(container, edits) {
76
121
  .sort((left, right) => left.start - right.start || (left.order ?? 0) - (right.order ?? 0));
77
122
  }
78
123
 
124
+ function sameSourcePath(left, right) {
125
+ const leftPath = left.targetSourcePath ?? left.sourcePath;
126
+ const rightPath = right.targetSourcePath ?? right.sourcePath;
127
+ return !leftPath || !rightPath || leftPath === rightPath;
128
+ }
129
+
79
130
  function duplicateEditKey(edit) {
80
- if (edit.editKind !== 'insert') return undefined;
131
+ if (edit.alreadyApplied) return undefined;
132
+ if (edit.editKind === 'insert') {
133
+ return [
134
+ 'insert',
135
+ edit.start,
136
+ edit.end,
137
+ edit.insertion?.mode,
138
+ edit.insertion?.anchorKey,
139
+ hashSemanticValue(edit.replacementSpanText ?? edit.replacement)
140
+ ].join(':');
141
+ }
81
142
  return [
82
- 'insert',
143
+ edit.editKind,
83
144
  edit.start,
84
145
  edit.end,
85
- edit.insertion?.mode,
86
- edit.insertion?.anchorKey,
87
- hashSemanticValue(edit.replacementSpanText ?? edit.replacement)
146
+ hashSemanticValue(edit.current),
147
+ hashSemanticValue(edit.replacement)
88
148
  ].join(':');
89
149
  }
90
150