@shapeshift-labs/frontier-lang-compiler 0.2.101 → 0.2.103

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 (23) hide show
  1. package/dist/declarations/import-adapter-core.d.ts +6 -0
  2. package/dist/declarations/native-project-admission-semantic-evidence.d.ts +34 -0
  3. package/dist/declarations/native-project-admission.d.ts +6 -10
  4. package/dist/declarations/semantic-edit-script.d.ts +3 -0
  5. package/dist/declarations/semantic-patch-bundle-overlaps.d.ts +1 -0
  6. package/dist/internal/index-impl/createLightweightNativeImport.js +9 -1
  7. package/dist/internal/index-impl/createProjectImportAdmissionRecord.js +14 -2
  8. package/dist/internal/index-impl/diffNativeSymbols.js +82 -1
  9. package/dist/internal/index-impl/importNativeSource.js +14 -14
  10. package/dist/internal/index-impl/nativeImportSemanticIndex.js +33 -0
  11. package/dist/internal/index-impl/projectImportAdmissionImportEvidence.js +1 -1
  12. package/dist/internal/index-impl/projectImportAdmissionSemanticWarnings.js +178 -0
  13. package/dist/internal/index-impl/projectImportAdmissionSummaries.js +22 -3
  14. package/dist/internal/index-impl/projectSemanticEditScriptToSource.js +12 -62
  15. package/dist/internal/index-impl/replaySemanticEditProjection.js +43 -63
  16. package/dist/internal/index-impl/semanticEditImportProjection.js +53 -0
  17. package/dist/internal/index-impl/semanticEditProjectionRecord.js +79 -0
  18. package/dist/internal/index-impl/semanticEditReplayAnchors.js +63 -0
  19. package/dist/internal/index-impl/semanticEditSourceRanges.js +5 -0
  20. package/dist/internal/index-impl/semanticPatchBundleAdmission.js +51 -2
  21. package/dist/internal/index-impl/semanticPatchBundleOverlaps.js +33 -16
  22. package/dist/semantic-import-regions.js +12 -1
  23. package/package.json +1 -1
@@ -98,6 +98,10 @@ export interface ImportNativeSourceOptions {
98
98
  readonly targetPath?: string;
99
99
  readonly targetHash?: string;
100
100
  readonly semanticIndex?: SemanticIndexRecord;
101
+ readonly ownershipRegions?: readonly SemanticImportOwnershipRegion[];
102
+ readonly semanticOwnershipRegions?: readonly SemanticImportOwnershipRegion[];
103
+ readonly patchHints?: readonly SemanticImportPatchHint[];
104
+ readonly semanticPatchHints?: readonly SemanticImportPatchHint[];
101
105
  readonly sourceMapId?: string;
102
106
  readonly sourceMaps?: readonly SourceMapRecord[];
103
107
  readonly universalAstId?: string;
@@ -112,6 +116,8 @@ export interface ImportNativeSourceOptions {
112
116
  export type NativeSourceImportResult = Omit<LanguageImportResult, 'metadata'> & {
113
117
  readonly nativeSource: NativeSourceNode;
114
118
  readonly semanticIndex?: SemanticIndexRecord;
119
+ readonly ownershipRegions: readonly SemanticImportOwnershipRegion[];
120
+ readonly patchHints: readonly SemanticImportPatchHint[];
115
121
  readonly universalAst: FrontierUniversalAstEnvelope;
116
122
  readonly metadata?: Record<string, unknown> & {
117
123
  readonly sourcePreservationRecords?: readonly SourcePreservationRecord[];
@@ -0,0 +1,34 @@
1
+ export type NativeProjectAdmissionSemanticEvidenceWarningCode =
2
+ | 'missing-ownership-regions'
3
+ | 'missing-patch-hints'
4
+ | (string & {});
5
+
6
+ export interface NativeProjectAdmissionSemanticEvidenceWarning {
7
+ readonly code: NativeProjectAdmissionSemanticEvidenceWarningCode;
8
+ readonly reasonCode: NativeProjectAdmissionSemanticEvidenceWarningCode;
9
+ readonly severity: 'warning' | string;
10
+ readonly message: string;
11
+ readonly action: string;
12
+ readonly sourcePath?: string;
13
+ readonly sourcePaths: readonly string[];
14
+ readonly semanticSymbols: number;
15
+ readonly ownershipRegions: number;
16
+ readonly patchHints: number;
17
+ readonly semanticImportExpected: boolean;
18
+ readonly changedSource: boolean;
19
+ }
20
+
21
+ export interface NativeProjectAdmissionSemanticEvidence {
22
+ readonly empty: boolean;
23
+ readonly emptySourceCount: number;
24
+ readonly emptySourcePaths: readonly string[];
25
+ readonly symbols: number;
26
+ readonly occurrences: number;
27
+ readonly relations: number;
28
+ readonly facts: number;
29
+ readonly evidenceRecords: number;
30
+ readonly warningCount: number;
31
+ readonly warningReasonCodes: readonly NativeProjectAdmissionSemanticEvidenceWarningCode[];
32
+ readonly warningSourcePaths: readonly string[];
33
+ readonly warnings: readonly NativeProjectAdmissionSemanticEvidenceWarning[];
34
+ }
@@ -2,7 +2,13 @@ import type { FrontierSourceLanguage, SemanticMergeReadiness } from '@shapeshift
2
2
  import type { NativeImportLossSummary } from './native-import-losses.js';
3
3
  import type { NativeImportResultContract } from './native-import-contracts.js';
4
4
  import type { NativeProjectImportResult } from './native-project.js';
5
+ import type { NativeProjectAdmissionSemanticEvidence } from './native-project-admission-semantic-evidence.js';
5
6
  import type { SemanticMergeCandidateAdmissionRecord, SemanticMergeCandidateOverlapRecord, SemanticMergeCandidateProjectionRisk } from './semantic-merge-candidates.js';
7
+ export type {
8
+ NativeProjectAdmissionSemanticEvidence,
9
+ NativeProjectAdmissionSemanticEvidenceWarning,
10
+ NativeProjectAdmissionSemanticEvidenceWarningCode
11
+ } from './native-project-admission-semantic-evidence.js';
6
12
  export type NativeProjectImportAdmissionAction = 'admit' | 'prioritize' | 'reject';
7
13
  export type NativeProjectImportAdmissionPriority = 'low' | 'normal' | 'high' | 'critical' | 'blocker';
8
14
  export type NativeProjectImportAdmissionRisk = 'low' | 'medium' | 'high' | 'unknown';
@@ -133,16 +139,6 @@ export interface NativeProjectAdmissionLanguages {
133
139
  readonly readinessRows: readonly NativeProjectAdmissionLanguageReadinessSummary[];
134
140
  readonly rows: readonly NativeProjectAdmissionLanguageSummary[];
135
141
  }
136
- export interface NativeProjectAdmissionSemanticEvidence {
137
- readonly empty: boolean;
138
- readonly emptySourceCount: number;
139
- readonly emptySourcePaths: readonly string[];
140
- readonly symbols: number;
141
- readonly occurrences: number;
142
- readonly relations: number;
143
- readonly facts: number;
144
- readonly evidenceRecords: number;
145
- }
146
142
  export type NativeProjectAdmissionSourceStalenessReason =
147
143
  | 'source-hash-mismatch'
148
144
  | 'content-hash-mismatch'
@@ -147,7 +147,10 @@ export interface SemanticEditProjectionEdit {
147
147
  readonly replacementBytes: number;
148
148
  readonly deletedTextHash?: string;
149
149
  readonly replacementTextHash?: string;
150
+ readonly deletedTextLineEndingStableHash?: string;
151
+ readonly replacementTextLineEndingStableHash?: string;
150
152
  readonly replacementSpanTextHash?: string;
153
+ readonly replacementSpanTextLineEndingStableHash?: string;
151
154
  readonly insertionMode?: string;
152
155
  readonly insertionAnchorKey?: string;
153
156
  readonly insertionAnchorSymbolName?: string;
@@ -71,6 +71,7 @@ export interface SemanticPatchBundleOverlapRecord {
71
71
  readonly sourceSignals: number;
72
72
  readonly baseHashMismatch: boolean;
73
73
  readonly targetHashMismatch: boolean;
74
+ readonly replayOutputHashMismatch: boolean;
74
75
  };
75
76
  readonly metadata?: Record<string, unknown>;
76
77
  }
@@ -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',
@@ -19,7 +19,7 @@ export function createProjectImportAdmissionRecord(projectResult,options={}){
19
19
  ...(projectResult?.mergeCandidates??[]),
20
20
  ...imports.flatMap((imported)=>imported?.mergeCandidates??[])
21
21
  ]);
22
- const importSummaries=projectAdmissionImports(imports,contract?.sources??[],mergeCandidates);
22
+ const importSummaries=projectAdmissionImports(imports,contract?.sources??[],mergeCandidates,projectResult);
23
23
  const languages=admissionLanguages(importSummaries);
24
24
  const semanticEvidence=admissionSemanticEvidence(projectResult,imports,importSummaries);
25
25
  const sourceStaleness=admissionSourceStaleness(imports,importSummaries,contract);
@@ -42,7 +42,10 @@ export function createProjectImportAdmissionRecord(projectResult,options={}){
42
42
  failedEvidenceIds,
43
43
  blockingLossIds:contract?.readiness?.blockingLossIds??lossSummary?.blockingLossIds??[]
44
44
  });
45
- const priorityReasons=admissionPriorityReasons({readiness,semanticEvidence,sourcePreservation,ownership,mergeCandidateRisk});
45
+ const priorityReasons=uniqueStrings([
46
+ ...admissionPriorityReasons({readiness,semanticEvidence,sourcePreservation,ownership,mergeCandidateRisk}),
47
+ ...semanticAdmissionWarningReasons(semanticEvidence)
48
+ ]);
46
49
  const action=rejectionReasons.length?'reject':priorityReasons.length?'prioritize':'admit';
47
50
  const priority=admissionPriority(action,readiness,sourcePreservation,mergeCandidateRisk);
48
51
  const mergeScore=admissionMergeScore({
@@ -221,6 +224,15 @@ function admissionSourcePreservationWithStaleness(sourcePreservation,sourceStale
221
224
  };
222
225
  }
223
226
 
227
+ function semanticAdmissionWarningReasons(semanticEvidence){
228
+ return (semanticEvidence?.warnings??[]).map((warning)=>{
229
+ const reasonCode=warning.reasonCode??warning.code;
230
+ const sourcePaths=warning.sourcePaths?.length?warning.sourcePaths:warning.sourcePath?[warning.sourcePath]:[];
231
+ const sourceText=sourcePaths.length?` for ${sourcePaths.join(', ')}`:'';
232
+ return `Project import semantic admission warning ${reasonCode}${sourceText}.`;
233
+ });
234
+ }
235
+
224
236
  function sourcePaths(records){
225
237
  return uniqueStrings(records.map((record)=>record.sourcePath).filter(Boolean));
226
238
  }
@@ -37,5 +37,86 @@ export function diffNativeSymbols(beforeSymbols, afterSymbols) {
37
37
  readiness: maxSemanticMergeReadiness(before?.readiness ?? 'ready', after?.readiness ?? 'ready')
38
38
  });
39
39
  }
40
- return changed;
40
+ return downgradeCoveredContainerSymbols(changed);
41
41
  }
42
+
43
+ function downgradeCoveredContainerSymbols(symbols) {
44
+ return symbols.filter((symbol) => !nativeDiffContainerCoveredByMorePreciseChange(symbol, symbols));
45
+ }
46
+
47
+ function nativeDiffContainerCoveredByMorePreciseChange(symbol, symbols) {
48
+ if (symbol.changeKind !== 'modified') return false;
49
+ if (!nativeDiffSymbolIsContainer(symbol)) return false;
50
+ if (nativeDiffSymbolHasOwnChange(symbol)) return false;
51
+ return symbols.some((candidate) => candidate !== symbol && nativeDiffSymbolIsMorePreciseNestedChange(candidate, symbol));
52
+ }
53
+
54
+ function nativeDiffSymbolHasOwnChange(symbol) {
55
+ return ((symbol.beforeSignatureHash ?? '') !== (symbol.afterSignatureHash ?? ''))
56
+ || ((symbol.beforeOwnershipKey ?? '') !== (symbol.afterOwnershipKey ?? ''))
57
+ || ((symbol.beforeNativeAstNodeId ?? '') !== (symbol.afterNativeAstNodeId ?? ''));
58
+ }
59
+
60
+ function nativeDiffSymbolIsMorePreciseNestedChange(candidate, container) {
61
+ if (candidate.changeKind === 'unchanged') return false;
62
+ if (nativeDiffSymbolIsContainer(candidate)) return false;
63
+ if ((candidate.ownershipKey ?? '') === (container.ownershipKey ?? '')) return false;
64
+ if (!nativeDiffAnySpanContains(container, candidate)) return false;
65
+ return nativeDiffNestedSymbolName(candidate, container) || nativeDiffSymbolIsMember(candidate);
66
+ }
67
+
68
+ function nativeDiffSymbolIsContainer(symbol) {
69
+ return nativeDiffContainerKinds.has(nativeDiffKind(symbol.ownershipRegionKind ?? symbol.kind));
70
+ }
71
+
72
+ function nativeDiffSymbolIsMember(symbol) {
73
+ return nativeDiffMemberKinds.has(nativeDiffKind(symbol.ownershipRegionKind ?? symbol.kind));
74
+ }
75
+
76
+ function nativeDiffNestedSymbolName(candidate, container) {
77
+ const candidateName = String(candidate.name ?? '');
78
+ const containerName = String(container.name ?? '');
79
+ return Boolean(containerName && candidateName && candidateName !== containerName && candidateName.startsWith(`${containerName}.`));
80
+ }
81
+
82
+ function nativeDiffAnySpanContains(container, candidate) {
83
+ return nativeDiffSymbolSpans(container).some((containerSpan) => nativeDiffSymbolSpans(candidate).some((candidateSpan) => (
84
+ nativeDiffSameSourcePath(candidateSpan, containerSpan) && nativeDiffSpanContains(containerSpan, candidateSpan)
85
+ )));
86
+ }
87
+
88
+ function nativeDiffSymbolSpans(symbol) {
89
+ return [symbol.sourceSpan, symbol.beforeSourceSpan, symbol.afterSourceSpan].filter(Boolean);
90
+ }
91
+
92
+ function nativeDiffSameSourcePath(left, right) {
93
+ const leftPath = left?.path;
94
+ const rightPath = right?.path;
95
+ return !leftPath || !rightPath || leftPath === rightPath;
96
+ }
97
+
98
+ function nativeDiffSpanContains(containerSpan, candidateSpan) {
99
+ const container = nativeDiffSpanRange(containerSpan);
100
+ const candidate = nativeDiffSpanRange(candidateSpan);
101
+ if (!container || !candidate) return false;
102
+ return container.start <= candidate.start && candidate.end <= container.end && (container.start !== candidate.start || container.end !== candidate.end);
103
+ }
104
+
105
+ function nativeDiffSpanRange(span) {
106
+ const startLine = Number(span?.startLine ?? span?.line ?? span?.start?.line);
107
+ const endLine = Number(span?.endLine ?? span?.end?.line ?? startLine);
108
+ if (!Number.isFinite(startLine) || !Number.isFinite(endLine)) return undefined;
109
+ const startColumn = Number(span?.startColumn ?? span?.column ?? span?.start?.column ?? 0);
110
+ const endColumn = Number(span?.endColumn ?? span?.end?.column ?? startColumn);
111
+ return {
112
+ start: startLine * 100000 + (Number.isFinite(startColumn) ? startColumn : 0),
113
+ end: endLine * 100000 + Math.max(Number.isFinite(startColumn) ? startColumn : 0, Number.isFinite(endColumn) ? endColumn : 0)
114
+ };
115
+ }
116
+
117
+ function nativeDiffKind(value) {
118
+ return String(value ?? '').toLowerCase();
119
+ }
120
+
121
+ const nativeDiffContainerKinds = new Set(['type', 'class', 'interface', 'trait', 'protocol', 'struct', 'enum', 'record']);
122
+ const nativeDiffMemberKinds = new Set(['body', 'method', 'function', 'property', 'declaration']);
@@ -1,17 +1,14 @@
1
1
  import{commonGeneratedTargetPath,idFragment}from'../../native-import-utils.js';import{inferSourceMapMappings,normalizeSourceMapMappings,normalizeSourceMaps}from'../../native-source-maps.js';import{createKernelSourcePreservationRecords,summarizeKernelSourcePreservationRecords}from'../../semantic-import-source-preservation.js';import{createDocument,createImportResult,createNativeAstRecord,createPatch,createSourceMapRecord,createUniversalAstEnvelope,hashSemanticValue,nativeSourceNode}from'@shapeshift-labs/frontier-lang-kernel';
2
2
  import{attachInputUniversalDialectRegistry}from'../../universal-dialect-registry.js';
3
3
  import{createLightweightSemanticLayers}from'./createLightweightSemanticLayers.js';
4
- import{attachNativeImportLossSummary}from'./attachNativeImportLossSummary.js';import{createLightweightNativeImport}from'./createLightweightNativeImport.js';import{createNativeSourcePreservation}from'./createNativeSourcePreservation.js';import{hasNativeExactAstEvidence}from'./hasNativeExactAstEvidence.js';import{normalizeNativeLossRecords}from'./normalizeNativeLossRecords.js';import{summarizeNativeImportLosses}from'./summarizeNativeImportLosses.js';import{unverifiedNativeAstLosses}from'./unverifiedNativeAstLosses.js';import{withNativeImportReadiness}from'./withNativeImportReadiness.js';
4
+ import{attachNativeImportLossSummary}from'./attachNativeImportLossSummary.js';import{createLightweightNativeImport}from'./createLightweightNativeImport.js';import{createNativeSourcePreservation}from'./createNativeSourcePreservation.js';import{hasNativeExactAstEvidence}from'./hasNativeExactAstEvidence.js';import{createNativeImportSemanticIndex}from'./nativeImportSemanticIndex.js';import{normalizeNativeLossRecords}from'./normalizeNativeLossRecords.js';import{summarizeNativeImportLosses}from'./summarizeNativeImportLosses.js';import{unverifiedNativeAstLosses}from'./unverifiedNativeAstLosses.js';import{withNativeImportReadiness}from'./withNativeImportReadiness.js';
5
5
  export function importNativeSource(input) {
6
6
  const language = input.language ?? input.nativeAst?.language;
7
7
  if (!language) throw new Error('importNativeSource requires a language or nativeAst.language');
8
8
  const sourcePath = input.sourcePath ?? input.nativeAst?.sourcePath;
9
9
  const declaredSourceHash = input.sourceHash ?? input.nativeAst?.sourceHash;
10
- const sourceHash = typeof input.sourceText === 'string'
11
- ? hashSemanticValue(input.sourceText)
12
- : declaredSourceHash ?? hashSemanticValue(input.nativeAst?.nodes ?? input.nativeAst ?? {});
13
- const targetPath = input.targetPath ?? input.target?.emitPath;
14
- const targetHash = input.targetHash;
10
+ const sourceHash = typeof input.sourceText === 'string' ? hashSemanticValue(input.sourceText) : declaredSourceHash ?? hashSemanticValue(input.nativeAst?.nodes ?? input.nativeAst ?? {});
11
+ const targetPath = input.targetPath ?? input.target?.emitPath; const targetHash = input.targetHash;
15
12
  const importIdPart = idFragment(input.id ?? input.nativeSourceId ?? sourcePath ?? language);
16
13
  const sourcePreservation = input.sourcePreservation ?? (typeof input.sourceText === 'string'
17
14
  ? createNativeSourcePreservation({
@@ -146,6 +143,7 @@ export function importNativeSource(input) {
146
143
  });
147
144
  const evidence = attachNativeImportLossSummary(baseEvidence, lossSummary);
148
145
  const semanticIndex = input.semanticIndex ?? lightweight?.semanticIndex;
146
+ const { ownershipRegions, patchHints, semanticIndexForResult } = createNativeImportSemanticIndex(input, lightweight, semanticIndex);
149
147
  const sourceMapMappings = normalizeSourceMapMappings(
150
148
  input.mappings ?? lightweight?.mappings ?? inferSourceMapMappings({
151
149
  semanticIndex,
@@ -174,7 +172,7 @@ export function importNativeSource(input) {
174
172
  target: input.target,
175
173
  targetPath: inferredTargetPath,
176
174
  targetHash,
177
- semanticIndexId: semanticIndex?.id,
175
+ semanticIndexId: semanticIndexForResult?.id,
178
176
  nativeAstId: nativeAst.id,
179
177
  nativeSourceId: nativeSource.id,
180
178
  mappings: sourceMapMappings,
@@ -191,7 +189,7 @@ export function importNativeSource(input) {
191
189
  nativeSources: [nativeSource],
192
190
  nativeAst,
193
191
  nativeSource,
194
- semanticIndex,
192
+ semanticIndex: semanticIndexForResult,
195
193
  evidence,
196
194
  losses,
197
195
  sourcePreservation,
@@ -213,16 +211,16 @@ export function importNativeSource(input) {
213
211
  evidence,
214
212
  nativeSource,
215
213
  nativeAst,
216
- semanticIndex
214
+ semanticIndex: semanticIndexForResult
217
215
  });
218
216
  const kernelSourcePreservationSummary = summarizeKernelSourcePreservationRecords(sourcePreservationRecords);
219
217
  const resultSourceMapMappings = sourceMaps.flatMap((sourceMap) => sourceMap.mappings ?? []);
220
- const semanticLayers=input.semanticLayers??createLightweightSemanticLayers({importIdPart,language,sourcePath,sourceHash,nativeSource,nativeAst,semanticIndex,sourceMaps,losses,evidence,sourcePreservationRecords});
218
+ const semanticLayers=input.semanticLayers??createLightweightSemanticLayers({importIdPart,language,sourcePath,sourceHash,nativeSource,nativeAst,semanticIndex:semanticIndexForResult,sourceMaps,losses,evidence,sourcePreservationRecords});
221
219
  let universalAst = createUniversalAstEnvelope({
222
220
  id: input.universalAstId ?? `universal_ast_${importIdPart}`,
223
221
  document,
224
222
  nativeSources: [nativeSource],
225
- semanticIndex,
223
+ semanticIndex: semanticIndexForResult,
226
224
  sourceMaps,
227
225
  losses,
228
226
  evidence,
@@ -262,7 +260,7 @@ export function importNativeSource(input) {
262
260
  metadata: {
263
261
  sourceLanguage: language,
264
262
  sourcePath,
265
- semanticIndexId: semanticIndex?.id,
263
+ semanticIndexId: semanticIndexForResult?.id,
266
264
  universalAstId: universalAst.id,
267
265
  sourceMapIds: sourceMaps.map((sourceMap) => sourceMap.id),
268
266
  ...(sourcePreservation ? {
@@ -287,14 +285,16 @@ export function importNativeSource(input) {
287
285
  document,
288
286
  patch,
289
287
  nativeAst,
290
- semanticIndex,
288
+ semanticIndex: semanticIndexForResult,
291
289
  universalAst,
292
290
  sourceMaps,
291
+ ownershipRegions,
292
+ patchHints: semanticIndexForResult?.patchHints ?? patchHints,
293
293
  losses,
294
294
  evidence,
295
295
  metadata: {
296
296
  nativeSourceId: nativeSource.id,
297
- semanticIndexId: semanticIndex?.id,
297
+ semanticIndexId: semanticIndexForResult?.id,
298
298
  universalAstId: universalAst.id,
299
299
  sourceMapIds: sourceMaps.map((sourceMap) => sourceMap.id),
300
300
  semanticStatus,
@@ -0,0 +1,33 @@
1
+ import{uniqueRecordsById}from'../../native-import-utils.js';
2
+ import{semanticOwnershipRegionsFromSemanticIndex,semanticPatchHintForRegion}from'../../semantic-import-regions.js';
3
+
4
+ export function createNativeImportSemanticIndex(input, lightweight, semanticIndex) {
5
+ const ownershipRegions = uniqueRecordsById([
6
+ ...(Array.isArray(input.ownershipRegions) ? input.ownershipRegions : []),
7
+ ...(Array.isArray(input.semanticOwnershipRegions) ? input.semanticOwnershipRegions : []),
8
+ ...(lightweight?.ownershipRegions ?? []),
9
+ ...semanticOwnershipRegionsFromSemanticIndex(semanticIndex),
10
+ ...(Array.isArray(input.universalAst?.ownershipRegions) ? input.universalAst.ownershipRegions : []),
11
+ ...(Array.isArray(input.metadata?.ownershipRegions) ? input.metadata.ownershipRegions : [])
12
+ ]);
13
+ const patchHints = uniqueRecordsById([
14
+ ...(Array.isArray(input.patchHints) ? input.patchHints : []),
15
+ ...(Array.isArray(input.semanticPatchHints) ? input.semanticPatchHints : []),
16
+ ...(lightweight?.patchHints ?? []),
17
+ ...(Array.isArray(semanticIndex?.patchHints) ? semanticIndex.patchHints : []),
18
+ ...(Array.isArray(input.universalAst?.patchHints) ? input.universalAst.patchHints : []),
19
+ ...(Array.isArray(input.metadata?.patchHints) ? input.metadata.patchHints : [])
20
+ ]);
21
+ const resultPatchHints = patchHints.length
22
+ ? patchHints
23
+ : ownershipRegions.map((region) => semanticPatchHintForRegion(region, 'needs-review'));
24
+ return {
25
+ ownershipRegions,
26
+ patchHints: resultPatchHints,
27
+ semanticIndexForResult: semanticIndex ? {
28
+ ...semanticIndex,
29
+ ownershipRegions,
30
+ patchHints: resultPatchHints
31
+ } : semanticIndex
32
+ };
33
+ }
@@ -1,5 +1,6 @@
1
1
  import{uniqueStrings}from'../../native-import-utils.js';
2
2
  import{nativeImportCategoryForLossKind}from'./nativeImportCategoryForLossKind.js';
3
+ export{summarizeSemanticAdmissionWarnings}from'./projectImportAdmissionSemanticWarnings.js';
3
4
 
4
5
  export function importLosses(imported){
5
6
  const nativeAst=imported?.nativeAst??imported?.nativeSource?.ast;
@@ -157,4 +158,3 @@ export function summarizeImportPreservation(imported,source){
157
158
  const quality=stale?'stale':missing?'missing':truncated||!exactSourceAvailable||sourcePreservationLosses.length?'lossy':'exact';
158
159
  return {quality,missing,stale,truncated,exactSourceAvailable,lossCount:sourcePreservationLosses.length,id:record?.id};
159
160
  }
160
-
@@ -0,0 +1,178 @@
1
+ import { uniqueRecordsById, uniqueStrings } from '../../native-import-utils.js';
2
+ import { semanticOwnershipRegionsFromSemanticIndex } from '../../semantic-import-regions.js';
3
+
4
+ export function summarizeSemanticAdmissionWarnings(imported, context = {}) {
5
+ const semanticIndex = imported?.semanticIndex ?? imported?.universalAst?.semanticIndex;
6
+ const symbols = semanticSymbolsForImport(imported, semanticIndex);
7
+ const ownershipRegions = semanticOwnershipRegionsForImport(imported, semanticIndex);
8
+ const patchHints = semanticPatchHintsForImport(imported, semanticIndex);
9
+ const sourcePath = firstString(context.sourcePath, context.source?.sourcePath, imported?.sourcePath, imported?.nativeSource?.sourcePath, imported?.nativeAst?.sourcePath, semanticIndex?.documents?.[0]?.path);
10
+ const semanticImportExpected = isSemanticImportExpected(imported, context);
11
+ const semanticImportExpectedEmpty = isSemanticImportExpectedEmpty(imported, context);
12
+ const changedSource = isChangedSemanticAdmissionSource(imported, { ...context, sourcePath });
13
+ const warnings = [];
14
+ if (semanticImportExpected && !semanticImportExpectedEmpty && changedSource && symbols.length > 0 && ownershipRegions.length === 0) {
15
+ warnings.push(semanticAdmissionWarning({
16
+ code: 'missing-ownership-regions',
17
+ message: 'Semantic import was expected for a changed source and produced symbols, but no ownership regions were available.',
18
+ action: 'rerun-sidecar-generation-with-ownership-regions',
19
+ sourcePath,
20
+ symbols,
21
+ ownershipRegions,
22
+ patchHints,
23
+ semanticImportExpected,
24
+ changedSource
25
+ }));
26
+ }
27
+ if (semanticImportExpected && !semanticImportExpectedEmpty && changedSource && symbols.length > 0 && patchHints.length === 0) {
28
+ warnings.push(semanticAdmissionWarning({
29
+ code: 'missing-patch-hints',
30
+ message: 'Semantic import was expected for a changed source and produced symbols, but no patch hints were available.',
31
+ action: 'generate-semantic-patch-hints',
32
+ sourcePath,
33
+ symbols,
34
+ ownershipRegions,
35
+ patchHints,
36
+ semanticImportExpected,
37
+ changedSource
38
+ }));
39
+ }
40
+ return {
41
+ semanticImportExpected,
42
+ semanticImportExpectedEmpty,
43
+ changedSource,
44
+ symbolCount: symbols.length,
45
+ ownershipRegionCount: ownershipRegions.length,
46
+ patchHintCount: patchHints.length,
47
+ warningCount: warnings.length,
48
+ reasonCodes: uniqueStrings(warnings.map((warning) => warning.reasonCode)),
49
+ warnings
50
+ };
51
+ }
52
+
53
+ function semanticAdmissionWarning(input) {
54
+ return {
55
+ code: input.code,
56
+ reasonCode: input.code,
57
+ severity: 'warning',
58
+ message: input.message,
59
+ action: input.action,
60
+ ...(input.sourcePath ? { sourcePath: input.sourcePath } : {}),
61
+ sourcePaths: uniqueStrings([input.sourcePath].filter(Boolean)),
62
+ semanticSymbols: input.symbols.length,
63
+ ownershipRegions: input.ownershipRegions.length,
64
+ patchHints: input.patchHints.length,
65
+ semanticImportExpected: input.semanticImportExpected,
66
+ changedSource: input.changedSource
67
+ };
68
+ }
69
+
70
+ function semanticSymbolsForImport(imported, semanticIndex) {
71
+ if (Array.isArray(semanticIndex?.symbols)) return semanticIndex.symbols;
72
+ for (const symbols of [
73
+ imported?.semanticSymbols,
74
+ imported?.symbols,
75
+ imported?.metadata?.semanticSymbols,
76
+ imported?.metadata?.symbols
77
+ ]) {
78
+ if (Array.isArray(symbols)) return symbols;
79
+ }
80
+ return [];
81
+ }
82
+
83
+ function semanticOwnershipRegionsForImport(imported, semanticIndex) {
84
+ return uniqueRecordsById([
85
+ ...(Array.isArray(imported?.ownershipRegions) ? imported.ownershipRegions : []),
86
+ ...(Array.isArray(imported?.semanticOwnershipRegions) ? imported.semanticOwnershipRegions : []),
87
+ ...semanticOwnershipRegionsFromSemanticIndex(semanticIndex),
88
+ ...(Array.isArray(imported?.universalAst?.ownershipRegions) ? imported.universalAst.ownershipRegions : []),
89
+ ...(Array.isArray(imported?.metadata?.ownershipRegions) ? imported.metadata.ownershipRegions : [])
90
+ ]);
91
+ }
92
+
93
+ function semanticPatchHintsForImport(imported, semanticIndex) {
94
+ return uniqueRecordsById([
95
+ ...(Array.isArray(imported?.patchHints) ? imported.patchHints : []),
96
+ ...(Array.isArray(imported?.semanticPatchHints) ? imported.semanticPatchHints : []),
97
+ ...(Array.isArray(semanticIndex?.patchHints) ? semanticIndex.patchHints : []),
98
+ ...(Array.isArray(imported?.universalAst?.patchHints) ? imported.universalAst.patchHints : []),
99
+ ...(Array.isArray(imported?.metadata?.patchHints) ? imported.metadata.patchHints : [])
100
+ ]);
101
+ }
102
+
103
+ function isSemanticImportExpected(imported, context) {
104
+ return semanticExpectationRecords(imported, context).some((entry) =>
105
+ entry.semanticImportExpected === true
106
+ || entry.expectedSemanticImport === true
107
+ || entry.semanticSidecarExpected === true
108
+ || entry.expected === true && looksLikeSemanticSidecarQuality(entry)
109
+ );
110
+ }
111
+
112
+ function isSemanticImportExpectedEmpty(imported, context) {
113
+ return semanticExpectationRecords(imported, context).some((entry) =>
114
+ entry.semanticImportExpectedEmpty === true
115
+ || entry.expectedSemanticImportEmpty === true
116
+ || entry.semanticSidecarExpectedEmpty === true
117
+ || entry.expectedEmpty === true && looksLikeSemanticSidecarQuality(entry)
118
+ );
119
+ }
120
+
121
+ function isChangedSemanticAdmissionSource(imported, context) {
122
+ const sourcePath = context.sourcePath;
123
+ const changedSourcePaths = uniqueStrings([
124
+ ...(context.projectResult?.changedSourcePaths ?? []),
125
+ ...(context.projectResult?.metadata?.changedSourcePaths ?? []),
126
+ ...(context.projectResult?.metadata?.semanticChangedSourcePaths ?? []),
127
+ ...(context.projectResult?.metadata?.semanticImportChangedSourcePaths ?? [])
128
+ ]);
129
+ return Boolean(
130
+ (context.candidates?.length ?? 0) > 0
131
+ || (sourcePath && changedSourcePaths.includes(sourcePath))
132
+ || semanticExpectationRecords(imported, context).some((entry) =>
133
+ entry.changedSource === true
134
+ || entry.sourceChanged === true
135
+ || entry.semanticSourceChanged === true
136
+ || entry.semanticImportChangedSource === true
137
+ )
138
+ );
139
+ }
140
+
141
+ function semanticExpectationRecords(imported, context) {
142
+ const nativeAst = imported?.nativeAst ?? imported?.nativeSource?.ast;
143
+ const semanticIndex = imported?.semanticIndex ?? imported?.universalAst?.semanticIndex;
144
+ return [
145
+ context.projectResult?.metadata,
146
+ context.source?.metadata,
147
+ imported?.metadata,
148
+ imported?.nativeSource?.metadata,
149
+ nativeAst?.metadata,
150
+ imported?.universalAst?.metadata,
151
+ imported?.patch?.metadata,
152
+ semanticIndex?.metadata,
153
+ imported?.semanticSidecarQuality,
154
+ imported?.sidecarQuality,
155
+ imported?.semanticSidecar?.quality,
156
+ imported?.sidecar?.quality,
157
+ imported?.metadata?.semanticSidecarQuality,
158
+ imported?.metadata?.sidecarQuality,
159
+ imported?.patch?.metadata?.semanticSidecarQuality
160
+ ].filter((entry) => entry && typeof entry === 'object');
161
+ }
162
+
163
+ function looksLikeSemanticSidecarQuality(value) {
164
+ return value && typeof value === 'object' && (
165
+ value.schema === 'frontier.lang.semanticSidecarQuality.v1'
166
+ || value.imported !== undefined
167
+ || value.expectedSatisfied !== undefined
168
+ || value.warningCount !== undefined
169
+ || value.proofSummary !== undefined
170
+ );
171
+ }
172
+
173
+ function firstString(...values) {
174
+ for (const value of values) {
175
+ if (value !== undefined && value !== null && String(value)) return String(value);
176
+ }
177
+ return undefined;
178
+ }