@shapeshift-labs/frontier-lang-compiler 0.2.24 → 0.2.25

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -229,10 +229,12 @@ const changeSet = diffNativeSources({
229
229
 
230
230
  console.log(changeSet.changedSymbols[0]?.changeKind); // "modified"
231
231
  console.log(changeSet.changedRegions[0]?.conflictKey); // semantic ownership key
232
+ console.log(changeSet.changedRegions[0]?.metadata.changedRegionProjection.reviewRequired); // true
233
+ console.log(changeSet.metadata.changedRegionProjectionSummary.autoMergeClaims); // 0
232
234
  console.log(changeSet.mergeCandidate.readiness); // merge-admission classification
233
235
  ```
234
236
 
235
- Use `diffNativeSourceImports` when the worker or runner already produced `importNativeSource` results. Body-only edits that the lightweight scanner cannot anchor to a symbol are still reported as file-level changed regions instead of being silently treated as safe.
237
+ Use `diffNativeSourceImports` when the worker or runner already produced `importNativeSource` results. Changed regions include a `metadata.changedRegionProjection` envelope with before/after source hashes, source-map links, ownership keys, readiness, and `autoMergeClaim: false` so swarm admission tools can score or port patches without treating semantic metadata as proof. Body-only edits that the lightweight scanner cannot anchor to a symbol are still reported as file-level changed regions instead of being silently treated as safe.
236
238
 
237
239
  Compile native source imports through the same reader/IR/writer facade that swarms use for sidecar evidence. Same-language targets preserve exact source when hashes match; cross-language targets emit declaration stubs until a real adapter provides stronger evidence:
238
240
 
package/bench/smoke.mjs CHANGED
@@ -7,6 +7,7 @@ import {
7
7
  createProjectionTargetLossMatrix,
8
8
  createNativeSourcePreservation,
9
9
  createSemanticImportSidecar,
10
+ diffNativeSources,
10
11
  importExternalSemanticIndex,
11
12
  importNativeSource,
12
13
  projectNativeImportToSource,
@@ -165,6 +166,20 @@ const regionScanDurationMs = performance.now() - regionScanStart;
165
166
  const regionScanSymbols = regionScanImports.reduce((sum, entry) => sum + entry.imported.semanticIndex.symbols.length, 0);
166
167
  const regionScanOwnershipRegions = regionScanImports.reduce((sum, entry) => sum + entry.sidecar.ownershipRegions.length, 0);
167
168
 
169
+ const changeProjectionStart = performance.now();
170
+ const changeProjectionSets = [];
171
+ for (let index = 0; index < 80; index += 1) {
172
+ changeProjectionSets.push(diffNativeSources({
173
+ language: 'javascript',
174
+ sourcePath: `src/change-projection-${index}.js`,
175
+ beforeSourceText: `export function changeProjection${index}() { return ${index}; }\n`,
176
+ afterSourceText: `export function changeProjection${index}() { return ${index + 1}; }\nexport const changeProjectionFlag${index} = true;\n`
177
+ }));
178
+ }
179
+ const changeProjectionDurationMs = performance.now() - changeProjectionStart;
180
+ const changedRegionProjections = changeProjectionSets.reduce((sum, changeSet) => sum + changeSet.metadata.changedRegionProjectionSummary.withProjection, 0);
181
+ const changedRegionProjectionSourceMapLinks = changeProjectionSets.reduce((sum, changeSet) => sum + changeSet.metadata.changedRegionProjectionSummary.sourceMapLinks, 0);
182
+
168
183
  const externalSemanticStart = performance.now();
169
184
  const externalSemanticImports = [];
170
185
  for (let index = 0; index < 100; index += 1) {
@@ -242,6 +257,10 @@ console.log(JSON.stringify({
242
257
  regionScanSymbols,
243
258
  regionScanOwnershipRegions,
244
259
  regionScanDurationMs: Number(regionScanDurationMs.toFixed(2)),
260
+ changeProjectionSets: changeProjectionSets.length,
261
+ changedRegionProjections,
262
+ changedRegionProjectionSourceMapLinks,
263
+ changeProjectionDurationMs: Number(changeProjectionDurationMs.toFixed(2)),
245
264
  externalSemanticImports: externalSemanticImports.length,
246
265
  externalSemanticSymbols,
247
266
  externalSemanticMappings,
package/dist/index.d.ts CHANGED
@@ -786,6 +786,91 @@ export interface SemanticImportSidecarOptions {
786
786
 
787
787
  export type NativeSourceChangeKind = 'added' | 'removed' | 'modified' | 'unchanged';
788
788
 
789
+ export interface NativeSourceChangeProjectionEndpoint {
790
+ readonly side: 'before' | 'after';
791
+ readonly importId?: string;
792
+ readonly sidecarId?: string;
793
+ readonly nativeSourceId?: string;
794
+ readonly nativeAstId?: string;
795
+ readonly semanticIndexId?: string;
796
+ readonly universalAstId?: string;
797
+ readonly sourcePath?: string;
798
+ readonly sourceHash?: string;
799
+ readonly sourcePreservationId?: string;
800
+ readonly exactSourceAvailable: boolean;
801
+ readonly ownershipRegionId?: string;
802
+ readonly ownershipKey?: string;
803
+ readonly ownershipRegionKind?: NativeImportRegionTaxonomyKind;
804
+ readonly sourceSpan?: SourceSpan;
805
+ readonly sourceMapIds: readonly string[];
806
+ readonly sourceMapMappingIds: readonly string[];
807
+ }
808
+
809
+ export interface NativeSourceChangeProjectionSourceMapLink {
810
+ readonly id: string;
811
+ readonly side: 'before' | 'after';
812
+ readonly sourceMapId?: string;
813
+ readonly sourceMapMappingId?: string;
814
+ readonly sourcePath?: string;
815
+ readonly sourceHash?: string;
816
+ readonly targetPath?: string;
817
+ readonly targetHash?: string;
818
+ readonly semanticSymbolId?: string;
819
+ readonly semanticOccurrenceId?: string;
820
+ readonly semanticNodeId?: string;
821
+ readonly nativeSourceId?: string;
822
+ readonly nativeAstNodeId?: string;
823
+ readonly precision?: string;
824
+ readonly sourceSpan?: SourceSpan;
825
+ readonly generatedSpan?: SourceMapMappingRecord['generatedSpan'];
826
+ readonly ownershipRegionId?: string;
827
+ readonly ownershipRegionKey?: string;
828
+ readonly ownershipRegionKind?: NativeImportRegionTaxonomyKind;
829
+ }
830
+
831
+ export interface NativeSourceChangeProjectionMetadata {
832
+ readonly schema: 'frontier.lang.changedRegionProjection.v1';
833
+ readonly id: string;
834
+ readonly reviewRequired: true;
835
+ readonly autoMergeClaim: false;
836
+ readonly changeKind: NativeSourceChangeKind;
837
+ readonly language?: FrontierSourceLanguage | string;
838
+ readonly sourcePath?: string;
839
+ readonly conflictKey: string;
840
+ readonly region: {
841
+ readonly id?: string;
842
+ readonly key?: string;
843
+ readonly kind?: NativeImportRegionTaxonomyKind;
844
+ readonly granularity?: string;
845
+ readonly precision?: string;
846
+ readonly sourceSpan?: SourceSpan;
847
+ readonly nativeAstNodeId?: string;
848
+ readonly symbolId?: string;
849
+ readonly symbolName?: string;
850
+ readonly symbolKind?: string;
851
+ };
852
+ readonly before?: NativeSourceChangeProjectionEndpoint;
853
+ readonly after?: NativeSourceChangeProjectionEndpoint;
854
+ readonly sourceMapLinks: readonly NativeSourceChangeProjectionSourceMapLink[];
855
+ readonly admission: {
856
+ readonly readiness: SemanticMergeReadiness;
857
+ readonly action: 'review-addition' | 'review-removal' | 'review-file' | 'review-port' | 'rerun-or-human-port' | string;
858
+ readonly reasons: readonly string[];
859
+ readonly conflictKeys: readonly string[];
860
+ };
861
+ }
862
+
863
+ export interface NativeSourceChangeProjectionSummary {
864
+ readonly schema: 'frontier.lang.changedRegionProjectionSummary.v1';
865
+ readonly total: number;
866
+ readonly withProjection: number;
867
+ readonly reviewRequired: number;
868
+ readonly autoMergeClaims: number;
869
+ readonly sourceMapLinks: number;
870
+ readonly byAction: Readonly<Record<string, number>>;
871
+ readonly byRegionKind: Readonly<Record<string, number>>;
872
+ }
873
+
789
874
  export interface NativeSourceChangeSymbol {
790
875
  readonly changeKind: NativeSourceChangeKind;
791
876
  readonly key: string;
@@ -813,6 +898,9 @@ export interface NativeSourceChangeSymbol {
813
898
  export interface NativeSourceChangeRegion extends SemanticImportOwnershipRegion {
814
899
  readonly changeKind: NativeSourceChangeKind;
815
900
  readonly conflictKey: string;
901
+ readonly metadata?: SemanticImportOwnershipRegion['metadata'] & {
902
+ readonly changedRegionProjection?: NativeSourceChangeProjectionMetadata;
903
+ };
816
904
  }
817
905
 
818
906
  export interface NativeSourceChangeSummary {
@@ -875,7 +963,9 @@ export interface NativeSourceChangeSet {
875
963
  readonly semanticIndex?: SemanticIndexRecord;
876
964
  readonly losses: readonly NativeAstLossRecord[];
877
965
  readonly summary: NativeSourceChangeSummary;
878
- readonly metadata?: Record<string, unknown>;
966
+ readonly metadata?: Record<string, unknown> & {
967
+ readonly changedRegionProjectionSummary?: NativeSourceChangeProjectionSummary;
968
+ };
879
969
  }
880
970
 
881
971
  export type NativeImporterAdapterExactness =
package/dist/index.js CHANGED
@@ -3158,6 +3158,25 @@ export function diffNativeSourceImports(input) {
3158
3158
  if (sourceChanged && changedSymbols.length === 0 && changedRegions.length === 0) {
3159
3159
  changedRegions = [fileLevelNativeChangeRegion({ language, sourcePath, beforeHash, afterHash, before, after })];
3160
3160
  }
3161
+ const readiness = maxSemanticMergeReadiness(
3162
+ maxSemanticMergeReadiness(nativeImportReadiness(before), nativeImportReadiness(after)),
3163
+ sourceChanged && changedSymbols.length === 0 ? 'needs-review' : 'ready'
3164
+ );
3165
+ const reasons = nativeSourceChangeReasons({ before, after, beforeHash, afterHash, changedSymbols, changedRegions, readiness });
3166
+ changedRegions = attachNativeChangeRegionProjectionMetadata(changedRegions, {
3167
+ before,
3168
+ after,
3169
+ beforeSidecar,
3170
+ afterSidecar,
3171
+ changedSymbols,
3172
+ language,
3173
+ sourcePath,
3174
+ beforeHash,
3175
+ afterHash,
3176
+ readiness,
3177
+ reasons
3178
+ });
3179
+ const changedRegionProjectionSummary = summarizeNativeChangedRegionProjections(changedRegions);
3161
3180
  const evidence = [{
3162
3181
  id: input.evidenceId ?? `evidence_${idPart}_native_source_diff`,
3163
3182
  kind: 'import',
@@ -3172,14 +3191,10 @@ export function diffNativeSourceImports(input) {
3172
3191
  sourceChanged,
3173
3192
  addedSymbols: changedSymbols.filter((symbol) => symbol.changeKind === 'added').length,
3174
3193
  removedSymbols: changedSymbols.filter((symbol) => symbol.changeKind === 'removed').length,
3175
- modifiedSymbols: changedSymbols.filter((symbol) => symbol.changeKind === 'modified').length
3194
+ modifiedSymbols: changedSymbols.filter((symbol) => symbol.changeKind === 'modified').length,
3195
+ changedRegionProjectionSummary
3176
3196
  }
3177
3197
  }];
3178
- const readiness = maxSemanticMergeReadiness(
3179
- maxSemanticMergeReadiness(nativeImportReadiness(before), nativeImportReadiness(after)),
3180
- sourceChanged && changedSymbols.length === 0 ? 'needs-review' : 'ready'
3181
- );
3182
- const reasons = nativeSourceChangeReasons({ before, after, beforeHash, afterHash, changedSymbols, changedRegions, readiness });
3183
3198
  const conflictKeys = uniqueStrings([
3184
3199
  ...changedSymbols.map((symbol) => symbol.conflictKey),
3185
3200
  ...changedRegions.map((region) => region.conflictKey ?? region.key ?? region.id),
@@ -3230,7 +3245,8 @@ export function diffNativeSourceImports(input) {
3230
3245
  beforeImportId: before?.id,
3231
3246
  afterImportId: after?.id,
3232
3247
  sourceChanged,
3233
- changeSummary: nativeSourceChangeSummary(changedSymbols, changedRegions, sourceChanged)
3248
+ changeSummary: nativeSourceChangeSummary(changedSymbols, changedRegions, sourceChanged),
3249
+ changedRegionProjectionSummary
3234
3250
  }
3235
3251
  });
3236
3252
  return {
@@ -3259,6 +3275,7 @@ export function diffNativeSourceImports(input) {
3259
3275
  afterSidecarId: afterSidecar?.id,
3260
3276
  beforeImportContract: before?.metadata?.importResultContract,
3261
3277
  afterImportContract: after?.metadata?.importResultContract,
3278
+ changedRegionProjectionSummary,
3262
3279
  ...input.metadata
3263
3280
  }
3264
3281
  };
@@ -3404,6 +3421,199 @@ function fileLevelNativeChangeRegion(input) {
3404
3421
  };
3405
3422
  }
3406
3423
 
3424
+ function attachNativeChangeRegionProjectionMetadata(regions, context) {
3425
+ return (regions ?? []).map((region) => {
3426
+ const projection = nativeChangedRegionProjectionMetadata(region, context);
3427
+ return {
3428
+ ...region,
3429
+ metadata: {
3430
+ ...(region.metadata ?? {}),
3431
+ changedRegionProjection: projection
3432
+ }
3433
+ };
3434
+ });
3435
+ }
3436
+
3437
+ function nativeChangedRegionProjectionMetadata(region, context) {
3438
+ const beforeRegion = findSemanticImportRegion(context.beforeSidecar, region);
3439
+ const afterRegion = findSemanticImportRegion(context.afterSidecar, region);
3440
+ const regionSymbols = (context.changedSymbols ?? []).filter((symbol) => nativeChangeSymbolTouchesRegion(symbol, region));
3441
+ const sourceMapLinks = uniqueRecordsById([
3442
+ ...nativeChangeProjectionSourceMapLinks(context.before, 'before', beforeRegion ?? region, regionSymbols),
3443
+ ...nativeChangeProjectionSourceMapLinks(context.after, 'after', afterRegion ?? region, regionSymbols)
3444
+ ]).slice(0, 24);
3445
+ const action = nativeChangedRegionProjectionAction(region, context.readiness);
3446
+ const conflictKeys = uniqueStrings([
3447
+ region.conflictKey,
3448
+ region.key ? `region:${region.key}` : undefined,
3449
+ region.id ? `region:${region.id}` : undefined,
3450
+ ...regionSymbols.map((symbol) => symbol.conflictKey)
3451
+ ].filter(Boolean));
3452
+ return {
3453
+ schema: 'frontier.lang.changedRegionProjection.v1',
3454
+ id: `changed_region_projection_${idFragment(region.conflictKey ?? region.key ?? region.id)}`,
3455
+ reviewRequired: true,
3456
+ autoMergeClaim: false,
3457
+ changeKind: region.changeKind,
3458
+ language: region.language ?? context.language,
3459
+ sourcePath: region.sourcePath ?? context.sourcePath,
3460
+ conflictKey: region.conflictKey,
3461
+ region: {
3462
+ id: region.id,
3463
+ key: region.key,
3464
+ kind: region.regionKind,
3465
+ granularity: region.granularity,
3466
+ precision: region.precision,
3467
+ sourceSpan: region.sourceSpan,
3468
+ nativeAstNodeId: region.nativeAstNodeId,
3469
+ symbolId: region.symbolId,
3470
+ symbolName: region.symbolName,
3471
+ symbolKind: region.symbolKind
3472
+ },
3473
+ before: nativeChangeProjectionEndpoint(context.before, context.beforeSidecar, beforeRegion ?? (region.changeKind === 'added' ? undefined : region), 'before'),
3474
+ after: nativeChangeProjectionEndpoint(context.after, context.afterSidecar, afterRegion ?? (region.changeKind === 'removed' ? undefined : region), 'after'),
3475
+ sourceMapLinks,
3476
+ admission: {
3477
+ readiness: context.readiness,
3478
+ action,
3479
+ reasons: context.reasons ?? [],
3480
+ conflictKeys
3481
+ }
3482
+ };
3483
+ }
3484
+
3485
+ function findSemanticImportRegion(sidecar, region) {
3486
+ return (sidecar?.ownershipRegions ?? []).find((candidate) => (
3487
+ (region.id && candidate.id === region.id) ||
3488
+ (region.key && candidate.key === region.key)
3489
+ ));
3490
+ }
3491
+
3492
+ function nativeChangeProjectionEndpoint(imported, sidecar, region, side) {
3493
+ if (!imported && !region) return undefined;
3494
+ const preservation = nativeImportSourcePreservationRecord(imported);
3495
+ const sourceMaps = imported?.sourceMaps ?? imported?.universalAst?.sourceMaps ?? [];
3496
+ const regionMappings = sourceMaps
3497
+ .flatMap((sourceMap) => (sourceMap?.mappings ?? []).map((mapping) => ({ sourceMap, mapping })))
3498
+ .filter(({ mapping }) => nativeChangeMappingTouchesRegion(mapping, region, []));
3499
+ return {
3500
+ side,
3501
+ importId: imported?.id,
3502
+ sidecarId: sidecar?.id,
3503
+ nativeSourceId: imported?.nativeSource?.id,
3504
+ nativeAstId: imported?.nativeAst?.id,
3505
+ semanticIndexId: imported?.semanticIndex?.id,
3506
+ universalAstId: imported?.universalAst?.id,
3507
+ sourcePath: imported?.sourcePath ?? region?.sourcePath,
3508
+ sourceHash: imported?.nativeSource?.sourceHash ?? imported?.nativeAst?.sourceHash ?? region?.sourceHash,
3509
+ sourcePreservationId: preservation?.id,
3510
+ exactSourceAvailable: preservation?.summary?.exactSourceAvailable === true,
3511
+ ownershipRegionId: region?.id,
3512
+ ownershipKey: region?.key,
3513
+ ownershipRegionKind: region?.regionKind,
3514
+ sourceSpan: region?.sourceSpan,
3515
+ sourceMapIds: sourceMaps.map((sourceMap) => sourceMap?.id).filter(Boolean),
3516
+ sourceMapMappingIds: regionMappings.map(({ mapping }) => mapping?.id).filter(Boolean)
3517
+ };
3518
+ }
3519
+
3520
+ function nativeChangeProjectionSourceMapLinks(imported, side, region, symbols) {
3521
+ if (!imported) return [];
3522
+ const sourceMaps = imported.sourceMaps ?? imported.universalAst?.sourceMaps ?? [];
3523
+ const links = [];
3524
+ for (const sourceMap of sourceMaps) {
3525
+ for (const mapping of sourceMap?.mappings ?? []) {
3526
+ if (!nativeChangeMappingTouchesRegion(mapping, region, symbols)) continue;
3527
+ links.push({
3528
+ id: `${side}:${sourceMap.id}:${mapping.id}`,
3529
+ side,
3530
+ sourceMapId: sourceMap.id,
3531
+ sourceMapMappingId: mapping.id,
3532
+ sourcePath: mapping.sourceSpan?.path ?? sourceMap.sourcePath ?? imported.sourcePath,
3533
+ sourceHash: sourceMap.sourceHash ?? imported.nativeSource?.sourceHash ?? imported.nativeAst?.sourceHash,
3534
+ targetPath: mapping.generatedSpan?.targetPath ?? sourceMap.targetPath,
3535
+ targetHash: mapping.generatedSpan?.targetHash ?? sourceMap.targetHash,
3536
+ semanticSymbolId: mapping.semanticSymbolId,
3537
+ semanticOccurrenceId: mapping.semanticOccurrenceId,
3538
+ semanticNodeId: mapping.semanticNodeId,
3539
+ nativeSourceId: mapping.nativeSourceId,
3540
+ nativeAstNodeId: mapping.nativeAstNodeId,
3541
+ precision: mapping.precision,
3542
+ sourceSpan: mapping.sourceSpan,
3543
+ generatedSpan: mapping.generatedSpan,
3544
+ ownershipRegionId: mapping.ownershipRegionId,
3545
+ ownershipRegionKey: mapping.ownershipRegionKey,
3546
+ ownershipRegionKind: mapping.ownershipRegionKind
3547
+ });
3548
+ }
3549
+ }
3550
+ return links;
3551
+ }
3552
+
3553
+ function nativeChangeMappingTouchesRegion(mapping, region, symbols) {
3554
+ if (!mapping || !region) return false;
3555
+ const symbolIds = new Set((symbols ?? []).map((symbol) => symbol.id).filter(Boolean));
3556
+ const occurrenceIds = new Set((symbols ?? []).map((symbol) => symbol.semanticOccurrenceId).filter(Boolean));
3557
+ const mappingIds = new Set((symbols ?? []).map((symbol) => symbol.sourceMapMappingId).filter(Boolean));
3558
+ if (mappingIds.has(mapping.id)) return true;
3559
+ if (region.id && mapping.ownershipRegionId === region.id) return true;
3560
+ if (region.key && mapping.ownershipRegionKey === region.key) return true;
3561
+ if (region.nativeAstNodeId && mapping.nativeAstNodeId === region.nativeAstNodeId) return true;
3562
+ if (symbolIds.has(mapping.semanticSymbolId)) return true;
3563
+ if (occurrenceIds.has(mapping.semanticOccurrenceId)) return true;
3564
+ if (region.granularity === 'file') {
3565
+ return !region.sourcePath || sourceSpanPathMatches(mapping.sourceSpan, region.sourcePath);
3566
+ }
3567
+ return false;
3568
+ }
3569
+
3570
+ function sourceSpanPathMatches(span, sourcePath) {
3571
+ if (!span || !sourcePath) return false;
3572
+ return span.path === sourcePath || span.sourceId === sourcePath;
3573
+ }
3574
+
3575
+ function nativeChangeSymbolTouchesRegion(symbol, region) {
3576
+ return Boolean(symbol && region && (
3577
+ (region.id && symbol.ownershipRegionId === region.id) ||
3578
+ (region.key && (
3579
+ symbol.ownershipKey === region.key ||
3580
+ symbol.beforeOwnershipKey === region.key ||
3581
+ symbol.afterOwnershipKey === region.key
3582
+ ))
3583
+ ));
3584
+ }
3585
+
3586
+ function nativeChangedRegionProjectionAction(region, readiness) {
3587
+ if (readiness === 'blocked') return 'rerun-or-human-port';
3588
+ if (region.changeKind === 'added') return 'review-addition';
3589
+ if (region.changeKind === 'removed') return 'review-removal';
3590
+ if (region.granularity === 'file') return 'review-file';
3591
+ return 'review-port';
3592
+ }
3593
+
3594
+ function nativeImportSourcePreservationRecord(imported) {
3595
+ return imported?.metadata?.sourcePreservation
3596
+ ?? imported?.nativeSource?.metadata?.sourcePreservation
3597
+ ?? imported?.nativeAst?.metadata?.sourcePreservation
3598
+ ?? imported?.universalAst?.metadata?.sourcePreservation;
3599
+ }
3600
+
3601
+ function summarizeNativeChangedRegionProjections(regions) {
3602
+ const projections = (regions ?? [])
3603
+ .map((region) => region?.metadata?.changedRegionProjection)
3604
+ .filter(Boolean);
3605
+ return {
3606
+ schema: 'frontier.lang.changedRegionProjectionSummary.v1',
3607
+ total: regions?.length ?? 0,
3608
+ withProjection: projections.length,
3609
+ reviewRequired: projections.filter((projection) => projection.reviewRequired === true).length,
3610
+ autoMergeClaims: projections.filter((projection) => projection.autoMergeClaim === true).length,
3611
+ sourceMapLinks: projections.reduce((sum, projection) => sum + (projection.sourceMapLinks?.length ?? 0), 0),
3612
+ byAction: countBy(projections.map((projection) => projection.admission?.action ?? 'unknown')),
3613
+ byRegionKind: countBy(projections.map((projection) => projection.region?.kind ?? 'unknown'))
3614
+ };
3615
+ }
3616
+
3407
3617
  function nativeImportReadiness(imported) {
3408
3618
  return imported?.metadata?.semanticMergeReadiness
3409
3619
  ?? imported?.metadata?.nativeImportLossSummary?.semanticMergeReadiness
@@ -3467,11 +3677,31 @@ function nativeChangeSpans(changedSymbols, changedRegions, input) {
3467
3677
  symbolId: region.symbolId,
3468
3678
  span: region.sourceSpan,
3469
3679
  conflictKey: region.conflictKey ?? `region:${region.key ?? region.id}`,
3470
- metadata: { changeKind: region.changeKind, regionKind: region.regionKind, granularity: region.granularity }
3680
+ metadata: {
3681
+ changeKind: region.changeKind,
3682
+ regionKind: region.regionKind,
3683
+ granularity: region.granularity,
3684
+ ...(region.metadata?.changedRegionProjection ? {
3685
+ changedRegionProjection: nativeChangedRegionProjectionSpanMetadata(region.metadata.changedRegionProjection)
3686
+ } : {})
3687
+ }
3471
3688
  }));
3472
3689
  return uniqueRecordsById([...symbolSpans, ...regionSpans]);
3473
3690
  }
3474
3691
 
3692
+ function nativeChangedRegionProjectionSpanMetadata(projection) {
3693
+ return {
3694
+ schema: projection.schema,
3695
+ id: projection.id,
3696
+ reviewRequired: projection.reviewRequired,
3697
+ autoMergeClaim: projection.autoMergeClaim,
3698
+ beforeSourceHash: projection.before?.sourceHash,
3699
+ afterSourceHash: projection.after?.sourceHash,
3700
+ sourceMapLinks: projection.sourceMapLinks?.length ?? 0,
3701
+ admission: projection.admission
3702
+ };
3703
+ }
3704
+
3475
3705
  function nativeSourceChangeSummary(changedSymbols, changedRegions, sourceChanged) {
3476
3706
  return {
3477
3707
  sourceChanged,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shapeshift-labs/frontier-lang-compiler",
3
- "version": "0.2.24",
3
+ "version": "0.2.25",
4
4
  "description": "Compiler facade for Frontier Lang source documents and language projection adapters.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",