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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/dist/declarations/bidirectional-target-change-evidence.d.ts +299 -0
  2. package/dist/declarations/bidirectional-target-change.d.ts +19 -120
  3. package/dist/declarations/import-adapter-core.d.ts +6 -0
  4. package/dist/declarations/native-project-admission.d.ts +43 -22
  5. package/dist/declarations/semantic-edit-replay-diagnostics.d.ts +24 -0
  6. package/dist/declarations/semantic-edit-script.d.ts +20 -15
  7. package/dist/declarations/semantic-lineage.d.ts +3 -21
  8. package/dist/declarations/semantic-merge-candidates.d.ts +39 -0
  9. package/dist/declarations/semantic-sidecar-admission.d.ts +14 -0
  10. package/dist/declarations/semantic-sidecar.d.ts +12 -14
  11. package/dist/internal/index-impl/bidirectionalTargetRoundtripEvidence.js +200 -0
  12. package/dist/internal/index-impl/createBidirectionalTargetChangeRecord.js +62 -17
  13. package/dist/internal/index-impl/createLightweightNativeImport.js +9 -1
  14. package/dist/internal/index-impl/createNativeSourcePreservation.js +16 -1
  15. package/dist/internal/index-impl/createProjectImportAdmissionRecord.js +151 -1
  16. package/dist/internal/index-impl/createSemanticImportSidecar.js +5 -0
  17. package/dist/internal/index-impl/createSemanticImportSidecarAdmission.js +29 -11
  18. package/dist/internal/index-impl/importNativeSource.js +14 -14
  19. package/dist/internal/index-impl/nativeChangeProjectionEndpoint.js +56 -16
  20. package/dist/internal/index-impl/nativeImportSemanticIndex.js +33 -0
  21. package/dist/internal/index-impl/projectImportAdmissionMergeScore.js +26 -74
  22. package/dist/internal/index-impl/projectImportAdmissionProjectionCoverage.js +74 -0
  23. package/dist/internal/index-impl/projectSemanticEditScriptToSource.js +39 -13
  24. package/dist/internal/index-impl/replaySemanticEditProjection.js +65 -23
  25. package/dist/internal/index-impl/semanticEditInsertionAnchors.js +8 -5
  26. package/dist/internal/index-impl/semanticEditReplayDiagnostics.js +167 -0
  27. package/dist/internal/index-impl/semanticEditSourceRanges.js +94 -15
  28. package/dist/internal/index-impl/semanticHistoryLineageResolution.js +21 -2
  29. package/dist/internal/index-impl/semanticLineageHashEvidence.js +97 -0
  30. package/dist/internal/index-impl/semanticLineageInferenceMatching.js +8 -0
  31. package/dist/internal/index-impl/semanticLineageResolutionRecords.js +18 -1
  32. package/dist/internal/index-impl/semanticMergeCandidateRecords.js +22 -2
  33. package/dist/internal/index-impl/semanticMergeCandidateScoreFacets.js +221 -0
  34. package/dist/internal/index-impl/semanticPatchBundleOverlaps.js +23 -1
  35. package/dist/internal/index-impl/sourcePreservationFromProjectionContext.js +9 -2
  36. package/dist/native-import-language-profiles.js +10 -2
  37. package/dist/native-region-scanner-js-helpers.js +8 -2
  38. package/dist/native-region-scanner-js-imports.js +7 -0
  39. package/dist/native-region-scanner-js.js +4 -4
  40. package/dist/native-region-scanner.js +2 -1
  41. package/dist/semantic-import-regions.js +18 -5
  42. package/dist/semantic-import-sidecar-admission-types.d.ts +14 -0
  43. package/dist/semantic-import-sidecar-entry.js +151 -7
  44. package/dist/semantic-import-sidecar-types.d.ts +18 -13
  45. package/dist/semantic-import-source-preservation-utils.js +55 -0
  46. package/dist/semantic-import-source-preservation.js +98 -3
  47. package/package.json +1 -1
@@ -22,7 +22,8 @@ export function createProjectImportAdmissionRecord(projectResult,options={}){
22
22
  const importSummaries=projectAdmissionImports(imports,contract?.sources??[],mergeCandidates);
23
23
  const languages=admissionLanguages(importSummaries);
24
24
  const semanticEvidence=admissionSemanticEvidence(projectResult,imports,importSummaries);
25
- const sourcePreservation=admissionSourcePreservation(importSummaries,contract);
25
+ const sourceStaleness=admissionSourceStaleness(imports,importSummaries,contract);
26
+ const sourcePreservation=admissionSourcePreservationWithStaleness(admissionSourcePreservation(importSummaries,contract),sourceStaleness);
26
27
  const ownership=admissionOwnership(contract,mergeCandidates);
27
28
  const mergeCandidateRisk=admissionMergeCandidates(projectResult,imports,mergeCandidates,lossSummary);
28
29
  const readiness=maxSemanticMergeReadiness(
@@ -54,6 +55,7 @@ export function createProjectImportAdmissionRecord(projectResult,options={}){
54
55
  readiness,
55
56
  sourceCount:imports.length,
56
57
  semanticEvidence,
58
+ sourceStaleness,
57
59
  sourcePreservation,
58
60
  ownership,
59
61
  mergeCandidateRisk,
@@ -71,6 +73,7 @@ export function createProjectImportAdmissionRecord(projectResult,options={}){
71
73
  sourceCount:imports.length,
72
74
  languages,
73
75
  semanticEvidence,
76
+ sourceStaleness,
74
77
  sourcePreservation,
75
78
  ownership,
76
79
  mergeCandidates:mergeCandidateRisk,
@@ -89,3 +92,150 @@ export function createProjectImportAdmissionRecord(projectResult,options={}){
89
92
  }
90
93
  };
91
94
  }
95
+
96
+ function admissionSourceStaleness(imports,importSummaries,contract){
97
+ const total=Math.max(imports.length,importSummaries.length,contract?.sources?.length??0);
98
+ const records=[];
99
+ for(let index=0;index<total;index+=1){
100
+ const record=sourceStalenessRecord(imports[index],importSummaries[index],contract?.sources?.[index]);
101
+ if(record.reasonCodes.length) records.push(record);
102
+ }
103
+ const staleRecords=records.filter((record)=>record.staleByContentHash||record.staleByBaseHash);
104
+ const contentHashRecords=records.filter((record)=>record.staleByContentHash);
105
+ const baseHashRecords=records.filter((record)=>record.staleByBaseHash);
106
+ const dirtyWorkspaceRecords=records.filter((record)=>record.dirtyWorkspace);
107
+ const unverifiedRecords=records.filter((record)=>record.unverifiedSourceHash);
108
+ return {
109
+ total,
110
+ stale:staleRecords.length,
111
+ contentHashStale:contentHashRecords.length,
112
+ baseHashStale:baseHashRecords.length,
113
+ dirtyWorkspace:dirtyWorkspaceRecords.length,
114
+ unverified:unverifiedRecords.length,
115
+ staleSourcePaths:sourcePaths(staleRecords),
116
+ contentHashStaleSourcePaths:sourcePaths(contentHashRecords),
117
+ baseHashStaleSourcePaths:sourcePaths(baseHashRecords),
118
+ dirtyWorkspaceSourcePaths:sourcePaths(dirtyWorkspaceRecords),
119
+ unverifiedSourcePaths:sourcePaths(unverifiedRecords),
120
+ records
121
+ };
122
+ }
123
+
124
+ function sourceStalenessRecord(imported,summary,source){
125
+ const nativeSource=imported?.nativeSource;
126
+ const nativeAst=imported?.nativeAst??nativeSource?.ast;
127
+ const preservation=imported?.metadata?.sourcePreservation
128
+ ??nativeSource?.metadata?.sourcePreservation
129
+ ??nativeAst?.metadata?.sourcePreservation
130
+ ??imported?.universalAst?.metadata?.sourcePreservation;
131
+ const metadata=[
132
+ imported?.metadata,
133
+ nativeSource?.metadata,
134
+ nativeAst?.metadata,
135
+ preservation?.metadata,
136
+ imported?.universalAst?.metadata,
137
+ imported?.patch?.metadata
138
+ ].filter((entry)=>entry&&typeof entry==='object');
139
+ const lossReasons=(imported?.losses??nativeAst?.losses??[]).flatMap((loss)=>[
140
+ loss?.reason,
141
+ loss?.metadata?.reason,
142
+ ...(Array.isArray(loss?.reasonCodes)?loss.reasonCodes:[]),
143
+ ...(Array.isArray(loss?.metadata?.reasonCodes)?loss.metadata.reasonCodes:[])
144
+ ]);
145
+ const observedReasonCodes=uniqueStrings([
146
+ ...metadata.flatMap((entry)=>[
147
+ entry.reason,
148
+ ...(Array.isArray(entry.reasonCodes)?entry.reasonCodes:[]),
149
+ ...(Array.isArray(entry.reasons)?entry.reasons:[])
150
+ ]),
151
+ ...lossReasons
152
+ ]);
153
+ const sourcePath=firstString(summary?.sourcePath,source?.sourcePath,imported?.sourcePath,nativeSource?.sourcePath,nativeAst?.sourcePath,preservation?.sourcePath);
154
+ const sourceHash=firstString(summary?.sourceHash,source?.sourceHash,imported?.sourceHash,nativeSource?.sourceHash,nativeAst?.sourceHash,preservation?.sourceHash);
155
+ const declaredSourceHash=firstMetadataString(metadata,'declaredSourceHash');
156
+ const contentHash=firstMetadataString(metadata,'currentContentHash','actualContentHash','contentHash')??sourceHash;
157
+ const declaredContentHash=firstMetadataString(metadata,'declaredContentHash','expectedContentHash','expectedSourceHash')??declaredSourceHash;
158
+ const sourceHashMismatch=Boolean(declaredSourceHash&&sourceHash&&declaredSourceHash!==sourceHash);
159
+ const contentHashMismatch=Boolean(declaredContentHash&&contentHash&&declaredContentHash!==contentHash);
160
+ const preservationHashMismatch=Boolean(preservation?.sourceHash&&sourceHash&&preservation.sourceHash!==sourceHash);
161
+ const sourceHashVerifiedFalse=metadata.some((entry)=>entry.sourceHashVerified===false);
162
+ const staleByContentHash=sourceHashMismatch
163
+ ||contentHashMismatch
164
+ ||preservationHashMismatch
165
+ ||(sourceHashVerifiedFalse&&Boolean(declaredSourceHash||declaredContentHash));
166
+ const baseHash=firstString(imported?.baseHash,imported?.patch?.baseHash,firstMetadataString(metadata,'baseHash'));
167
+ const expectedBaseHash=firstMetadataString(metadata,'expectedBaseHash','declaredBaseHash','sourceBaseHash');
168
+ const currentBaseHash=firstMetadataString(metadata,'currentBaseHash','actualBaseHash','headBaseHash','workspaceBaseHash');
169
+ const staleByBaseHash=Boolean(
170
+ expectedBaseHash&&currentBaseHash&&expectedBaseHash!==currentBaseHash
171
+ )||metadata.some((entry)=>entry.baseHashVerified===false)||observedReasonCodes.includes('base-hash-mismatch');
172
+ const dirtyWorkspace=metadata.some((entry)=>
173
+ entry.dirtyWorkspace===true
174
+ ||entry.workspaceDirty===true
175
+ ||entry.worktreeDirty===true
176
+ ||entry.dirtyWorktree===true
177
+ )||observedReasonCodes.some((reason)=>reason==='dirty-workspace'||reason==='workspace-dirty'||reason==='dirty-worktree');
178
+ const unverifiedSourceHash=sourceHashVerifiedFalse&&!staleByContentHash;
179
+ const reasonCodes=uniqueStrings([
180
+ ...(sourceHashMismatch?['source-hash-mismatch']:[]),
181
+ ...(contentHashMismatch?['content-hash-mismatch']:[]),
182
+ ...(preservationHashMismatch?['source-preservation-hash-mismatch']:[]),
183
+ ...(staleByContentHash&&sourceHashVerifiedFalse?['source-hash-unverified']:[]),
184
+ ...(staleByBaseHash?['base-hash-mismatch']:[]),
185
+ ...(dirtyWorkspace?['dirty-workspace']:[]),
186
+ ...(unverifiedSourceHash?['source-hash-unverified']:[])
187
+ ]);
188
+ return {
189
+ ...(sourcePath?{sourcePath}:{}),
190
+ ...(sourceHash?{sourceHash}:{}),
191
+ ...(declaredSourceHash?{declaredSourceHash}:{}),
192
+ ...(contentHash?{contentHash}:{}),
193
+ ...(declaredContentHash?{declaredContentHash}:{}),
194
+ ...(baseHash?{baseHash}:{}),
195
+ ...(expectedBaseHash?{expectedBaseHash}:{}),
196
+ ...(currentBaseHash?{currentBaseHash}:{}),
197
+ staleByContentHash,
198
+ staleByBaseHash,
199
+ dirtyWorkspace,
200
+ unverifiedSourceHash,
201
+ reasonCodes
202
+ };
203
+ }
204
+
205
+ function admissionSourcePreservationWithStaleness(sourcePreservation,sourceStaleness){
206
+ const stale=sourceStaleness.stale;
207
+ const quality=stale>0?'stale':sourcePreservation.quality==='stale'
208
+ ? sourcePreservation.missing>0?'missing':sourcePreservation.lossy>0||sourcePreservation.truncated?'lossy':sourcePreservation.total===0?'empty':'exact'
209
+ : sourcePreservation.quality;
210
+ return {
211
+ ...sourcePreservation,
212
+ quality,
213
+ stale,
214
+ staleSourcePaths:sourceStaleness.staleSourcePaths,
215
+ contentHashStale:sourceStaleness.contentHashStale,
216
+ baseHashStale:sourceStaleness.baseHashStale,
217
+ dirtyWorkspace:sourceStaleness.dirtyWorkspace,
218
+ contentHashStaleSourcePaths:sourceStaleness.contentHashStaleSourcePaths,
219
+ baseHashStaleSourcePaths:sourceStaleness.baseHashStaleSourcePaths,
220
+ dirtyWorkspaceSourcePaths:sourceStaleness.dirtyWorkspaceSourcePaths
221
+ };
222
+ }
223
+
224
+ function sourcePaths(records){
225
+ return uniqueStrings(records.map((record)=>record.sourcePath).filter(Boolean));
226
+ }
227
+
228
+ function firstMetadataString(metadata,...keys){
229
+ for(const key of keys){
230
+ const value=firstString(...metadata.map((entry)=>entry?.[key]));
231
+ if(value) return value;
232
+ }
233
+ return undefined;
234
+ }
235
+
236
+ function firstString(...values){
237
+ for(const value of values){
238
+ if(value!==undefined&&value!==null&&String(value)) return String(value);
239
+ }
240
+ return undefined;
241
+ }
@@ -29,6 +29,7 @@ export function createSemanticImportSidecar(importResult, options = {}) {
29
29
  const patchHints = ownershipRegions.map((region) => semanticPatchHintForRegion(region, readiness, options));
30
30
  const quality = createSemanticImportSidecarQuality({
31
31
  expected: options.expected === true || options.semanticImportExpected === true,
32
+ expectedEmpty: options.expectedEmpty === true || options.semanticImportExpectedEmpty === true,
32
33
  importEntries,
33
34
  symbols,
34
35
  ownershipRegions,
@@ -130,8 +131,12 @@ export function createSemanticImportSidecar(importResult, options = {}) {
130
131
  patchHints: patchHints.length,
131
132
  evidenceWarnings: quality.emptyEvidenceWarnings.length,
132
133
  semanticImportExpected: quality.expected,
134
+ semanticImportExpectedEmpty: quality.expectedEmpty,
133
135
  semanticImportExpectedSatisfied: quality.expectedSatisfied,
134
136
  semanticImportExpectedMissingReasonCodes: quality.expectedMissingReasonCodes,
137
+ semanticImportRecordClassification: quality.record.classification,
138
+ semanticImportRecordReasonCode: quality.record.reasonCode,
139
+ semanticImportRecordAction: quality.record.action,
135
140
  readiness,
136
141
  emptySemanticIndex: symbols.length === 0
137
142
  },
@@ -1,3 +1,5 @@
1
+ import { semanticImportSidecarQualityRecord } from '../../semantic-import-sidecar-entry.js';
2
+
1
3
  function sidecarSourcePaths(importEntries) {
2
4
  return [...new Set(importEntries.map((entry) => entry.sourcePath).filter(Boolean))];
3
5
  }
@@ -15,10 +17,19 @@ function sidecarQualityWarning(code, message, action, sourcePaths) {
15
17
  export function createSemanticImportSidecarQuality(input) {
16
18
  const { importEntries, symbols, ownershipRegions, patchHints, proofSpec, evidence, readiness } = input;
17
19
  const expected = input.expected === true;
20
+ const expectedEmpty = input.expectedEmpty === true || input.semanticImportExpectedEmpty === true;
18
21
  const sourcePaths = sidecarSourcePaths(importEntries);
19
22
  const importCount = importEntries.length;
23
+ const record = semanticImportSidecarQualityRecord({
24
+ expected,
25
+ expectedEmpty,
26
+ importCount,
27
+ symbolCount: symbols.length,
28
+ sourcePaths
29
+ });
30
+ const expectedEmptySatisfied = record.classification === 'expected-empty';
20
31
  const warnings = [];
21
- if (expected && importCount === 0) warnings.push(sidecarQualityWarning(
32
+ if ((expected || expectedEmpty) && importCount === 0) warnings.push(sidecarQualityWarning(
22
33
  'expected-semantic-import-missing',
23
34
  'Semantic import was expected but no import entries were selected.',
24
35
  'check-semantic-import-include-globs-and-workspace-paths',
@@ -30,31 +41,31 @@ export function createSemanticImportSidecarQuality(input) {
30
41
  'run-native-import',
31
42
  sourcePaths
32
43
  ));
33
- if (expected && importCount > 0 && symbols.length === 0) warnings.push(sidecarQualityWarning(
44
+ if (!expectedEmptySatisfied && expected && importCount > 0 && symbols.length === 0) warnings.push(sidecarQualityWarning(
34
45
  'expected-semantic-import-empty',
35
46
  'Semantic import was expected but selected imports produced zero semantic symbols.',
36
47
  'rerun-importer-with-semantic-source-selection',
37
48
  sourcePaths
38
49
  ));
39
- if (importCount > 0 && symbols.length === 0) warnings.push(sidecarQualityWarning(
50
+ if (!expectedEmptySatisfied && importCount > 0 && symbols.length === 0) warnings.push(sidecarQualityWarning(
40
51
  'empty-semantic-index',
41
52
  'Semantic sidecar has import entries but no semantic symbols.',
42
53
  'rerun-importer-with-semantic-index',
43
54
  sourcePaths
44
55
  ));
45
- if (importCount > 0 && ownershipRegions.length === 0) warnings.push(sidecarQualityWarning(
56
+ if (!expectedEmptySatisfied && importCount > 0 && ownershipRegions.length === 0) warnings.push(sidecarQualityWarning(
46
57
  'missing-ownership-regions',
47
58
  'Semantic sidecar has no ownership regions for safe merge ownership.',
48
59
  'rerun-sidecar-generation-with-ownership-regions',
49
60
  sourcePaths
50
61
  ));
51
- if (importCount > 0 && patchHints.length === 0) warnings.push(sidecarQualityWarning(
62
+ if (!expectedEmptySatisfied && importCount > 0 && patchHints.length === 0) warnings.push(sidecarQualityWarning(
52
63
  'missing-patch-hints',
53
64
  'Semantic sidecar has no patch hints.',
54
65
  'generate-semantic-patch-hints',
55
66
  sourcePaths
56
67
  ));
57
- if (importCount > 0 && evidence.length === 0) warnings.push(sidecarQualityWarning(
68
+ if (!expectedEmptySatisfied && importCount > 0 && evidence.length === 0) warnings.push(sidecarQualityWarning(
58
69
  'empty-evidence',
59
70
  'Semantic sidecar has no evidence records.',
60
71
  'attach-semantic-import-evidence',
@@ -116,16 +127,18 @@ export function createSemanticImportSidecarQuality(input) {
116
127
  warning.code === 'missing-ownership-regions' ||
117
128
  warning.code === 'missing-patch-hints'
118
129
  ));
119
- const expectedMissingReasonCodes = expected
120
- ? emptyEvidenceWarnings.map((warning) => warning.code)
121
- : [];
122
- const expectedSatisfied = !expected || (
130
+ const expectedSatisfied = expectedEmpty
131
+ ? expectedEmptySatisfied
132
+ : !expected || (
123
133
  importCount > 0 &&
124
134
  symbols.length > 0 &&
125
135
  ownershipRegions.length > 0 &&
126
136
  patchHints.length > 0 &&
127
137
  evidence.length > 0
128
138
  );
139
+ const expectedMissingReasonCodes = (expected || expectedEmpty) && !expectedSatisfied
140
+ ? emptyEvidenceWarnings.map((warning) => warning.code)
141
+ : [];
129
142
  const proofSummary = {
130
143
  total: proofSpec.total,
131
144
  obligations: proofSpec.obligations,
@@ -143,12 +156,14 @@ export function createSemanticImportSidecarQuality(input) {
143
156
  return {
144
157
  schema: 'frontier.lang.semanticSidecarQuality.v1',
145
158
  expected,
159
+ expectedEmpty,
146
160
  expectedSatisfied,
147
161
  expectedMissingReasonCodes,
148
162
  selected: importCount > 0,
149
- eligible: importCount > 0 && emptyEvidenceWarnings.length === 0 && proofSpec.failed === 0 && readiness !== 'blocked',
163
+ eligible: record.classification === 'useful' && emptyEvidenceWarnings.length === 0 && proofSpec.failed === 0 && readiness !== 'blocked',
150
164
  imported: importCount > 0,
151
165
  importCount,
166
+ record,
152
167
  symbolCount: symbols.length,
153
168
  ownershipRegionCount: ownershipRegions.length,
154
169
  patchHintCount: patchHints.length,
@@ -164,6 +179,7 @@ export function createSemanticImportSidecarAdmission(quality, readiness) {
164
179
  return {
165
180
  schema: 'frontier.lang.semanticSidecarAdmission.v1',
166
181
  expected: quality.expected,
182
+ expectedEmpty: quality.expectedEmpty,
167
183
  expectedSatisfied: quality.expectedSatisfied,
168
184
  expectedMissingReasonCodes: quality.expectedMissingReasonCodes,
169
185
  selected: quality.selected,
@@ -172,6 +188,7 @@ export function createSemanticImportSidecarAdmission(quality, readiness) {
172
188
  importCount: quality.importCount,
173
189
  readiness,
174
190
  action: sidecarAdmissionAction(quality, readiness),
191
+ record: quality.record,
175
192
  counts: {
176
193
  symbols: quality.symbolCount,
177
194
  ownershipRegions: quality.ownershipRegionCount,
@@ -191,6 +208,7 @@ function sidecarAdmissionAction(quality, readiness) {
191
208
  if (!quality.imported) return 'reject-missing-imports';
192
209
  if (readiness === 'blocked') return 'reject-blocked';
193
210
  if (quality.proofSummary.failed > 0) return 'reject-failed-proof';
211
+ if (quality.record?.classification === 'expected-empty') return 'skip-expected-empty';
194
212
  if (quality.emptyEvidenceWarnings.length > 0) return 'reject-empty-evidence';
195
213
  if (!quality.eligible) return 'reject-quality';
196
214
  if (sidecarProofReviewObligations(quality.proofSummary) > 0) return 'review-proof-obligations';
@@ -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,
@@ -1,4 +1,4 @@
1
- import{nativeChangeMappingTouchesRegion}from'./nativeChangeMappingTouchesRegion.js';import{nativeImportSourcePreservationRecord}from'./nativeImportSourcePreservationRecord.js';
1
+ import{uniqueStrings}from'../../native-import-utils.js';import{nativeChangeMappingTouchesRegion}from'./nativeChangeMappingTouchesRegion.js';import{nativeImportSourcePreservationRecord}from'./nativeImportSourcePreservationRecord.js';
2
2
  export function nativeChangeProjectionEndpoint(imported, sidecar, region, side) {
3
3
  if (!imported && !region) return undefined;
4
4
  const preservation = nativeImportSourcePreservationRecord(imported);
@@ -6,23 +6,63 @@ export function nativeChangeProjectionEndpoint(imported, sidecar, region, side)
6
6
  const regionMappings = sourceMaps
7
7
  .flatMap((sourceMap) => (sourceMap?.mappings ?? []).map((mapping) => ({ sourceMap, mapping })))
8
8
  .filter(({ mapping }) => nativeChangeMappingTouchesRegion(mapping, region, []));
9
+ const sourceMapIds = uniqueStrings(sourceMaps.map((sourceMap) => sourceMap?.id));
10
+ const sourceMapMappingIds = uniqueStrings(regionMappings.map(({ mapping }) => mapping?.id));
11
+ const importId = imported?.id;
12
+ const nativeSourceId = imported?.nativeSource?.id;
13
+ const nativeAstId = imported?.nativeAst?.id;
14
+ const semanticIndexId = imported?.semanticIndex?.id;
15
+ const universalAstId = imported?.universalAst?.id;
16
+ const sourcePath = imported?.sourcePath ?? region?.sourcePath;
17
+ const sourceHash = imported?.nativeSource?.sourceHash ?? imported?.nativeAst?.sourceHash ?? region?.sourceHash;
18
+ const sourcePreservationId = preservation?.id;
19
+ const exactSourceAvailable = preservation?.summary?.exactSourceAvailable === true;
20
+ const ownershipRegionId = region?.id;
21
+ const ownershipKey = region?.key;
22
+ const ownershipRegionKind = region?.regionKind;
23
+ const sourceSpan = region?.sourceSpan;
24
+ const identity = compactRecord({
25
+ schema: 'frontier.lang.nativeChangeProjectionEndpointIdentity.v1',
26
+ version: 1,
27
+ side,
28
+ importId,
29
+ nativeSourceId,
30
+ nativeAstId,
31
+ semanticIndexId,
32
+ universalAstId,
33
+ sourcePath,
34
+ sourceHash,
35
+ sourcePreservationId,
36
+ exactSourceAvailable,
37
+ ownershipRegionId,
38
+ ownershipKey,
39
+ ownershipRegionKind,
40
+ sourceSpan,
41
+ sourceMapIds,
42
+ sourceMapMappingIds
43
+ });
9
44
  return {
10
45
  side,
11
- importId: imported?.id,
46
+ importId,
12
47
  sidecarId: sidecar?.id,
13
- nativeSourceId: imported?.nativeSource?.id,
14
- nativeAstId: imported?.nativeAst?.id,
15
- semanticIndexId: imported?.semanticIndex?.id,
16
- universalAstId: imported?.universalAst?.id,
17
- sourcePath: imported?.sourcePath ?? region?.sourcePath,
18
- sourceHash: imported?.nativeSource?.sourceHash ?? imported?.nativeAst?.sourceHash ?? region?.sourceHash,
19
- sourcePreservationId: preservation?.id,
20
- exactSourceAvailable: preservation?.summary?.exactSourceAvailable === true,
21
- ownershipRegionId: region?.id,
22
- ownershipKey: region?.key,
23
- ownershipRegionKind: region?.regionKind,
24
- sourceSpan: region?.sourceSpan,
25
- sourceMapIds: sourceMaps.map((sourceMap) => sourceMap?.id).filter(Boolean),
26
- sourceMapMappingIds: regionMappings.map(({ mapping }) => mapping?.id).filter(Boolean)
48
+ nativeSourceId,
49
+ nativeAstId,
50
+ semanticIndexId,
51
+ universalAstId,
52
+ sourcePath,
53
+ sourceHash,
54
+ sourcePreservationId,
55
+ exactSourceAvailable,
56
+ ownershipRegionId,
57
+ ownershipKey,
58
+ ownershipRegionKind,
59
+ sourceSpan,
60
+ sourceMapIds,
61
+ sourceMapMappingIds,
62
+ identity
27
63
  };
28
64
  }
65
+
66
+ function compactRecord(value) {
67
+ return Object.fromEntries(Object.entries(value ?? {}).filter(([, entry]) => entry !== undefined && (!Array.isArray(entry) || entry.length > 0)));
68
+ }
@@ -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,4 +1,5 @@
1
1
  import{uniqueRecordsById,uniqueStrings}from'../../native-import-utils.js';
2
+ import{targetProjectionCoverageSignals}from'./projectImportAdmissionProjectionCoverage.js';
2
3
 
3
4
  const scoreWeights=Object.freeze({
4
5
  semanticEvidence:22,
@@ -95,15 +96,35 @@ function sourcePreservationScore(input){
95
96
 
96
97
  function sourceFreshnessScore(input){
97
98
  const sourceCount=Math.max(input.sourceCount??0,input.sourcePreservation.total,1);
98
- const fresh=Math.max(0,sourceCount-input.sourcePreservation.stale);
99
+ const sourceStaleness=input.sourceStaleness??{};
100
+ const stale=sourceStaleness.stale??input.sourcePreservation.stale;
101
+ const contentHashStale=sourceStaleness.contentHashStale??input.sourcePreservation.contentHashStale??0;
102
+ const baseHashStale=sourceStaleness.baseHashStale??input.sourcePreservation.baseHashStale??0;
103
+ const dirtyWorkspace=sourceStaleness.dirtyWorkspace??input.sourcePreservation.dirtyWorkspace??0;
104
+ const fresh=Math.max(0,sourceCount-stale);
99
105
  const score=roundScore(fresh*100/sourceCount);
100
106
  return scoreComponent('sourceFreshness',score,[
101
- ...(input.sourcePreservation.stale?[
102
- `Project import has stale source hashes for ${input.sourcePreservation.stale} source(s).`
107
+ ...(contentHashStale?[
108
+ `Project import has stale content hashes for ${contentHashStale} source(s).`
109
+ ]:[]),
110
+ ...(baseHashStale?[
111
+ `Project import has stale base hashes for ${baseHashStale} source(s).`
112
+ ]:[]),
113
+ ...(!contentHashStale&&!baseHashStale&&stale?[
114
+ `Project import has stale source hashes for ${stale} source(s).`
115
+ ]:[]),
116
+ ...(dirtyWorkspace&&!stale?[
117
+ `Project workspace is marked dirty for ${dirtyWorkspace} source(s), but no content or base hash staleness was detected.`
103
118
  ]:[])
104
119
  ],{
105
- stale:input.sourcePreservation.stale,
106
- staleSourcePaths:input.sourcePreservation.staleSourcePaths,
120
+ stale,
121
+ contentHashStale,
122
+ baseHashStale,
123
+ dirtyWorkspace,
124
+ staleSourcePaths:sourceStaleness.staleSourcePaths??input.sourcePreservation.staleSourcePaths,
125
+ contentHashStaleSourcePaths:sourceStaleness.contentHashStaleSourcePaths??input.sourcePreservation.contentHashStaleSourcePaths??[],
126
+ baseHashStaleSourcePaths:sourceStaleness.baseHashStaleSourcePaths??input.sourcePreservation.baseHashStaleSourcePaths??[],
127
+ dirtyWorkspaceSourcePaths:sourceStaleness.dirtyWorkspaceSourcePaths??input.sourcePreservation.dirtyWorkspaceSourcePaths??[],
107
128
  checkedSources:sourceCount
108
129
  });
109
130
  }
@@ -186,75 +207,6 @@ function targetProjectionCoverageScore(input){
186
207
  ],coverage);
187
208
  }
188
209
 
189
- function targetProjectionCoverageSignals(input){
190
- const entries=targetProjectionEntries(input.projectResult,input.imports);
191
- const matrices=projectionMatrices(input.projectResult,input.imports);
192
- for(const matrix of matrices){
193
- for(const language of matrix?.languages??[]) entries.push(...(language?.targets??[]));
194
- }
195
- const sourceMapSummary=input.contract?.sourceMaps??{};
196
- const summary=matrices.reduce((current,matrix)=>{
197
- current.exactSourceProjection+=matrix?.summary?.exactSourceProjection??0;
198
- current.targetAdapterProjection+=matrix?.summary?.targetAdapterProjection??0;
199
- current.missingAdapters+=matrix?.summary?.missingAdapters??0;
200
- current.unsupportedTargetFeatures+=matrix?.summary?.unsupportedTargetFeatures??0;
201
- return current;
202
- },{exactSourceProjection:0,targetAdapterProjection:0,missingAdapters:0,unsupportedTargetFeatures:0});
203
- const targetEntries=entries.length;
204
- const supportedTargets=entries.filter((entry)=>entry?.supported===true).length;
205
- const adapterProjectionTargets=entries.filter((entry)=>
206
- entry?.lossClass==='targetAdapterProjection'||entry?.lossClass==='exactSourceProjection'||entry?.adapter||entry?.adapterKind==='targetProjection'
207
- ).length+summary.targetAdapterProjection+summary.exactSourceProjection;
208
- const readinessValues=entries.map((entry)=>readinessScore[entry?.readiness]??45);
209
- const readinessAverage=readinessValues.length?readinessValues.reduce((sum,value)=>sum+value,0)/readinessValues.length:0;
210
- return {
211
- targetEntries,
212
- supportedTargets,
213
- adapterProjectionTargets,
214
- exactSourceProjection:Math.max(summary.exactSourceProjection,input.sourcePreservation.exactSourceAvailable??0),
215
- targetAdapterProjection:summary.targetAdapterProjection,
216
- missingAdapters:summary.missingAdapters+entries.filter((entry)=>entry?.lossClass==='missingAdapter'||entry?.supported===false).length,
217
- unsupportedTargetFeatures:summary.unsupportedTargetFeatures+entries.filter((entry)=>entry?.lossClass==='unsupportedTargetFeatures').length,
218
- readinessScore:roundScore(readinessAverage),
219
- sourceMapMappings:sourceMapSummary.mappingCount??0,
220
- generatedRangeMappings:sourceMapSummary.generatedRangeMappings??0,
221
- targetPaths:sourceMapSummary.targetPaths?.length??0,
222
- adapterGeneratedRanges:input.contract?.adapterCoverage?.generatedRanges??0
223
- };
224
- }
225
-
226
- function targetProjectionEntries(projectResult,imports){
227
- return [
228
- projectResult?.targetCoverage,
229
- projectResult?.metadata?.targetCoverage,
230
- projectResult?.metadata?.targetProjectionCoverage,
231
- ...(projectResult?.targetCoverages??[]),
232
- ...(projectResult?.metadata?.targetCoverages??[]),
233
- ...(imports??[]).flatMap((imported)=>[
234
- imported?.targetCoverage,
235
- imported?.metadata?.targetCoverage,
236
- imported?.metadata?.targetProjectionCoverage,
237
- ...(imported?.targetCoverages??[]),
238
- ...(imported?.metadata?.targetCoverages??[])
239
- ])
240
- ].flatMap((entry)=>Array.isArray(entry)?entry:[entry]).filter((entry)=>entry&&typeof entry==='object'&&(entry.target||entry.lossClass||entry.supported!==undefined));
241
- }
242
-
243
- function projectionMatrices(projectResult,imports){
244
- return [
245
- projectResult?.projectionMatrix,
246
- projectResult?.metadata?.projectionMatrix,
247
- ...(projectResult?.projectionMatrices??[]),
248
- ...(projectResult?.metadata?.projectionMatrices??[]),
249
- ...(imports??[]).flatMap((imported)=>[
250
- imported?.projectionMatrix,
251
- imported?.metadata?.projectionMatrix,
252
- ...(imported?.projectionMatrices??[]),
253
- ...(imported?.metadata?.projectionMatrices??[])
254
- ])
255
- ].filter((matrix)=>matrix?.kind==='frontier.lang.projectionTargetLossMatrix'||Array.isArray(matrix?.languages));
256
- }
257
-
258
210
  function admissionEvidenceRecords(projectResult,imports){
259
211
  return uniqueRecordsById([
260
212
  ...(projectResult?.evidence??[]),