@shapeshift-labs/frontier-lang-compiler 0.2.64 → 0.2.66

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 (32) hide show
  1. package/README.md +31 -6
  2. package/dist/declarations/import-adapter-core.d.ts +3 -0
  3. package/dist/declarations/native-project-admission.d.ts +18 -0
  4. package/dist/declarations/semantic-merge-candidates.d.ts +200 -0
  5. package/dist/declarations/semantic-merge-conflicts.d.ts +12 -0
  6. package/dist/declarations/semantic-sidecar.d.ts +8 -3
  7. package/dist/index.d.ts +1 -0
  8. package/dist/index.js +1 -0
  9. package/dist/internal/index-impl/attachExternalOwnership.js +18 -10
  10. package/dist/internal/index-impl/createSemanticImportSidecar.js +6 -0
  11. package/dist/internal/index-impl/createSemanticSlice.js +3 -2
  12. package/dist/internal/index-impl/diffNativeSourceImports.js +3 -2
  13. package/dist/internal/index-impl/externalSemanticBase.js +1 -0
  14. package/dist/internal/index-impl/importExternalSemanticIndex.js +4 -0
  15. package/dist/internal/index-impl/projectImportAdmissionSummaries.js +31 -6
  16. package/dist/internal/index-impl/runNativeImporterAdapter.js +1 -1
  17. package/dist/internal/index-impl/semanticMergeCandidateRecordInternals.js +314 -0
  18. package/dist/internal/index-impl/semanticMergeCandidateRecords.js +241 -0
  19. package/dist/internal/index-impl/withExternalEmptyLoss.js +1 -0
  20. package/dist/language-adapter-package-contracts.js +6 -6
  21. package/dist/lightweight-dependency-language.js +8 -0
  22. package/dist/native-region-scanner-core.js +42 -10
  23. package/dist/native-region-scanner-js-helpers.js +2 -0
  24. package/dist/native-region-scanner-js-imports.js +111 -0
  25. package/dist/native-region-scanner-js.js +111 -28
  26. package/examples/js-frontier-rust-workbench-adapters.mjs +89 -0
  27. package/examples/js-frontier-rust-workbench-bounds.mjs +4 -3
  28. package/examples/js-frontier-rust-workbench-client.mjs +78 -59
  29. package/examples/js-frontier-rust-workbench-html.mjs +20 -13
  30. package/examples/js-frontier-rust-workbench-styles.mjs +9 -16
  31. package/examples/js-frontier-rust-workbench.mjs +67 -121
  32. package/package.json +1 -1
package/README.md CHANGED
@@ -36,17 +36,19 @@ npm run build
36
36
  node examples/native-js-to-rust-demo.mjs
37
37
  ```
38
38
 
39
- Run the interactive Frontier-style workbench with editable TypeScript and Rust panes:
39
+ Run the interactive Frontier-style workbench with a submitted TypeScript source pane,
40
+ Frontier graph/JSON pane, and independent Rust/Python projection panes:
40
41
 
41
42
  ```sh
42
43
  npm run demo:ts-rust -- --port 4177
43
44
  ```
44
45
 
45
46
  The workbench converts only when `Run` is pressed. TypeScript edits project through
46
- the Frontier semantic graph into Rust scaffolding; Rust edits project back through
47
- the graph into TypeScript scaffolding. The middle pane shows symbols, relations,
48
- source maps, readiness, losses, patch hints, and the explicit supported/review-only/
49
- unsupported bounds for the current direction.
47
+ the Frontier semantic graph into Rust and Python scaffolding. The middle pane shows
48
+ symbols, relations, source maps, readiness, losses, patch hints, and the explicit
49
+ supported/review-only/unsupported bounds for the projection. Run
50
+ `npm run demo:ts-rust:smoke` to verify the conversion output and layout scaffold
51
+ without starting the server.
50
52
 
51
53
  The demo prints JavaScript source, the Frontier universal AST/semantic-index summary,
52
54
  Rust declaration stubs, a host-adapter Rust projection, and a direct Frontier-source
@@ -117,11 +119,12 @@ const importedIndex = importExternalSemanticIndex({
117
119
  });
118
120
 
119
121
  console.log(importedIndex.semanticIndex.symbols.length);
122
+ console.log(importedIndex.ownershipRegions[0]?.key);
120
123
  console.log(importedIndex.summary.sourceMapMappings);
121
124
  console.log(importedIndex.readiness.readiness); // "ready-with-losses" or review-required
122
125
  ```
123
126
 
124
- External semantic-index imports create Frontier `SemanticIndexRecord`, `SourceMapRecord`, evidence, losses, ownership facts, and a universal AST envelope. They are a bridge from existing language servers/indexers into semantic merge tooling; they do not claim full parser AST coverage, macro expansion, type checking, comments/trivia preservation, or lossless cross-language code generation by themselves.
127
+ External semantic-index imports create Frontier `SemanticIndexRecord`, `SourceMapRecord`, evidence, losses, ownership facts, first-class `ownershipRegions`, and a universal AST envelope. They are a bridge from existing language servers/indexers into semantic merge tooling; they do not claim full parser AST coverage, macro expansion, type checking, comments/trivia preservation, or lossless cross-language code generation by themselves.
125
128
 
126
129
  Native imports include source maps, semantic merge candidates, and a loss summary for admission queues and dashboards. Informational losses produce `ready-with-losses`, warning losses produce `needs-review`, and error losses or failed import evidence produce `blocked`:
127
130
 
@@ -137,6 +140,28 @@ console.log(readiness.readiness);
137
140
 
138
141
  The loss taxonomy separates broad scanner limits from specific round-trip risks such as conditional compilation, reflection, overload/type-inference gaps, comments/trivia preservation, source-map approximation, parser diagnostics, and target projection loss. These records are evidence labels for merge admission; they are not claims that the lightweight scanner expanded macros, evaluated inactive branches, resolved overloads, or ran a type checker.
139
142
 
143
+ Semantic merge candidates also expose compiler-normalized admission records for coordinator queues:
144
+
145
+ ```js
146
+ import {
147
+ createSemanticMergeCandidateAdmissionRecord,
148
+ querySemanticMergeCandidateAdmissionOverlaps,
149
+ sortSemanticMergeCandidateAdmissionRecords
150
+ } from '@shapeshift-labs/frontier-lang-compiler';
151
+
152
+ const record = createSemanticMergeCandidateAdmissionRecord(changeSet);
153
+
154
+ console.log(record.changedSemanticRegions);
155
+ console.log(record.sourceHashes.baseHash, record.sourceHashes.targetHash);
156
+ console.log(record.conflictKeys, record.evidenceIds);
157
+ console.log(record.projectionRisk, record.readiness, record.readinessSortKey);
158
+
159
+ const queue = sortSemanticMergeCandidateAdmissionRecords([record, otherRecord]);
160
+ const overlaps = querySemanticMergeCandidateAdmissionOverlaps(queue);
161
+ ```
162
+
163
+ These candidate records are compact merge-admission evidence. They preserve changed semantic regions, source/base/target hashes, conflict keys, evidence IDs, projection risk, readiness, and overlap pairs so swarm coordinators can sort likely-ready candidates first and detect conflicting regions before patch review.
164
+
140
165
  High-risk native features also have explicit evidence policies. These policies are advisory in this package: they tell a swarm or admission queue what evidence is missing without silently changing the existing readiness classification.
141
166
 
142
167
  ```js
@@ -154,6 +154,8 @@ export interface ExternalSemanticIndexImportSummary {
154
154
  readonly occurrences: number;
155
155
  readonly relations: number;
156
156
  readonly facts: number;
157
+ readonly ownershipRegions: number;
158
+ readonly ownershipRegionKinds: readonly string[];
157
159
  readonly sourceMapMappings: number;
158
160
  readonly losses: number;
159
161
  readonly readiness: SemanticMergeReadiness;
@@ -170,6 +172,7 @@ export interface ExternalSemanticIndexImportResult {
170
172
  readonly semanticIndex: SemanticIndexRecord;
171
173
  readonly universalAst: FrontierUniversalAstEnvelope;
172
174
  readonly sourceMaps: readonly SourceMapRecord[];
175
+ readonly ownershipRegions: readonly SemanticImportOwnershipRegion[];
173
176
  readonly losses: readonly NativeAstLossRecord[];
174
177
  readonly evidence: readonly EvidenceRecord[];
175
178
  readonly readiness: NativeImportReadinessClassification;
@@ -2,6 +2,7 @@ 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 { SemanticMergeCandidateAdmissionRecord, SemanticMergeCandidateOverlapRecord, SemanticMergeCandidateProjectionRisk } from './semantic-merge-candidates.js';
5
6
 
6
7
  export type NativeProjectImportAdmissionAction = 'admit' | 'prioritize' | 'reject';
7
8
  export type NativeProjectImportAdmissionPriority = 'low' | 'normal' | 'high' | 'critical' | 'blocker';
@@ -78,10 +79,27 @@ export interface NativeProjectAdmissionMergeCandidates {
78
79
  readonly highestRisk: NativeProjectImportAdmissionRisk;
79
80
  readonly byRisk: Readonly<Record<string, number>>;
80
81
  readonly byReadiness: Readonly<Record<string, number>>;
82
+ readonly byProjectionRisk: Readonly<Record<string, number>>;
81
83
  readonly highRiskCandidateIds: readonly string[];
82
84
  readonly reviewCandidateIds: readonly string[];
83
85
  readonly blockedCandidateIds: readonly string[];
86
+ readonly highProjectionRiskCandidateIds: readonly string[];
84
87
  readonly conflictKeys: readonly string[];
88
+ readonly readinessOrderCandidateIds: readonly string[];
89
+ readonly changedSemanticRegions: {
90
+ readonly total: number;
91
+ readonly byKind: Readonly<Record<string, number>>;
92
+ readonly conflictKeys: readonly string[];
93
+ };
94
+ readonly overlaps: {
95
+ readonly total: number;
96
+ readonly candidateIds: readonly string[];
97
+ readonly conflictKeys: readonly string[];
98
+ readonly sourcePaths: readonly string[];
99
+ readonly pairs: readonly SemanticMergeCandidateOverlapRecord[];
100
+ };
101
+ readonly records: readonly SemanticMergeCandidateAdmissionRecord[];
102
+ readonly projectionRisk?: SemanticMergeCandidateProjectionRisk;
85
103
  readonly patchRisk?: NativeProjectImportAdmissionRisk;
86
104
  }
87
105
 
@@ -0,0 +1,200 @@
1
+ import type {
2
+ EvidenceRecord,
3
+ FrontierSourceLanguage,
4
+ SemanticMergeCandidateRecord,
5
+ SemanticMergeReadiness,
6
+ SourceSpan
7
+ } from '@shapeshift-labs/frontier-lang-kernel';
8
+ import type { NativeSourceChangeKind, NativeSourceChangeSet } from './native-diff.js';
9
+ import type { SemanticMergeConflictSummary } from './semantic-merge-conflicts.js';
10
+
11
+ export type SemanticMergeCandidateProjectionRisk = 'low' | 'medium' | 'high' | 'unknown';
12
+
13
+ export interface SemanticMergeCandidateChangedRegion {
14
+ readonly id?: string;
15
+ readonly key?: string;
16
+ readonly conflictKey?: string;
17
+ readonly changeKind?: NativeSourceChangeKind | string;
18
+ readonly regionKind?: string;
19
+ readonly granularity?: string;
20
+ readonly precision?: string;
21
+ readonly projectionRisk?: SemanticMergeCandidateProjectionRisk;
22
+ readonly language?: FrontierSourceLanguage | string;
23
+ readonly sourcePath?: string;
24
+ readonly sourceHash?: string;
25
+ readonly baseHash?: string;
26
+ readonly targetHash?: string;
27
+ readonly symbolId?: string;
28
+ readonly symbolName?: string;
29
+ readonly symbolKind?: string;
30
+ readonly semanticNodeId?: string;
31
+ readonly nativeAstNodeId?: string;
32
+ readonly sourceSpan?: SourceSpan;
33
+ readonly sourceMapLinkIds?: readonly string[];
34
+ readonly sourceMapIds?: readonly string[];
35
+ readonly sourceMapMappingIds?: readonly string[];
36
+ readonly admission?: {
37
+ readonly readiness?: SemanticMergeReadiness | string;
38
+ readonly action?: string;
39
+ readonly reasonCodes?: readonly string[];
40
+ readonly conflictKeys?: readonly string[];
41
+ };
42
+ }
43
+
44
+ export interface SemanticMergeCandidateOverlapRecord {
45
+ readonly schema: 'frontier.lang.semanticMergeCandidateOverlap.v1';
46
+ readonly id: string;
47
+ readonly overlapKind: 'conflict-key' | 'region-key' | 'source-span' | string;
48
+ readonly risk: 'medium' | 'high' | string;
49
+ readonly readiness: SemanticMergeReadiness | string;
50
+ readonly recordIds: readonly string[];
51
+ readonly candidateIds: readonly string[];
52
+ readonly regionIds: readonly string[];
53
+ readonly regionKeys: readonly string[];
54
+ readonly conflictKeys: readonly string[];
55
+ readonly sourcePath?: string;
56
+ readonly leftRegion: Partial<SemanticMergeCandidateChangedRegion>;
57
+ readonly rightRegion: Partial<SemanticMergeCandidateChangedRegion>;
58
+ }
59
+
60
+ export interface SemanticMergeCandidateAdmissionRecord {
61
+ readonly kind: 'frontier.lang.semanticMergeCandidateAdmissionRecord';
62
+ readonly version: 1;
63
+ readonly schema: 'frontier.lang.semanticMergeCandidateAdmissionRecord.v1';
64
+ readonly id: string;
65
+ readonly candidateId?: string;
66
+ readonly importResultId?: string;
67
+ readonly patchId?: string;
68
+ readonly language?: FrontierSourceLanguage | string;
69
+ readonly sourcePath?: string;
70
+ readonly readiness: SemanticMergeReadiness | string;
71
+ readonly readinessSortKey: number;
72
+ readonly projectionRisk: SemanticMergeCandidateProjectionRisk;
73
+ readonly sourceHashes: {
74
+ readonly baseHash?: string;
75
+ readonly targetHash?: string;
76
+ readonly values: readonly string[];
77
+ };
78
+ readonly baseHash?: string;
79
+ readonly targetHash?: string;
80
+ readonly changedSemanticRegions: readonly SemanticMergeCandidateChangedRegion[];
81
+ readonly conflictKeys: readonly string[];
82
+ readonly evidenceIds: readonly string[];
83
+ readonly proofIds: readonly string[];
84
+ readonly overlapSummary: {
85
+ readonly total: number;
86
+ readonly hasOverlaps: boolean;
87
+ readonly byKind: Readonly<Record<string, number>>;
88
+ readonly conflictKeys: readonly string[];
89
+ readonly pairs: readonly SemanticMergeCandidateOverlapRecord[];
90
+ };
91
+ readonly admission: {
92
+ readonly readiness: SemanticMergeReadiness | string;
93
+ readonly reviewRequired: boolean;
94
+ readonly action: 'admit' | 'prioritize-review' | 'block' | string;
95
+ readonly sortKey: number;
96
+ readonly reasonCodes: readonly string[];
97
+ readonly conflictKeys: readonly string[];
98
+ };
99
+ readonly index: {
100
+ readonly candidateIds: readonly string[];
101
+ readonly importResultIds: readonly string[];
102
+ readonly patchIds: readonly string[];
103
+ readonly sourcePaths: readonly string[];
104
+ readonly sourceHashes: readonly string[];
105
+ readonly baseHashes: readonly string[];
106
+ readonly targetHashes: readonly string[];
107
+ readonly regionIds: readonly string[];
108
+ readonly regionKeys: readonly string[];
109
+ readonly regionKinds: readonly string[];
110
+ readonly conflictKeys: readonly string[];
111
+ readonly evidenceIds: readonly string[];
112
+ readonly proofIds: readonly string[];
113
+ readonly readinesses: readonly string[];
114
+ readonly projectionRisks: readonly string[];
115
+ };
116
+ readonly summary: {
117
+ readonly changedSemanticRegions: number;
118
+ readonly conflictKeys: number;
119
+ readonly evidenceIds: number;
120
+ readonly proofIds: number;
121
+ readonly overlaps: number;
122
+ readonly readiness: SemanticMergeReadiness | string;
123
+ readonly projectionRisk: SemanticMergeCandidateProjectionRisk;
124
+ readonly reviewRequired: boolean;
125
+ };
126
+ readonly metadata?: Record<string, unknown> & {
127
+ readonly conflictSummary?: SemanticMergeConflictSummary;
128
+ };
129
+ }
130
+
131
+ export type SemanticMergeCandidateAdmissionInput =
132
+ | NativeSourceChangeSet
133
+ | SemanticMergeCandidateRecord
134
+ | SemanticMergeCandidateAdmissionRecord
135
+ | Record<string, unknown>;
136
+
137
+ export interface CreateSemanticMergeCandidateAdmissionRecordOptions {
138
+ readonly id?: string;
139
+ readonly changeSet?: NativeSourceChangeSet;
140
+ readonly candidate?: SemanticMergeCandidateRecord | Record<string, unknown>;
141
+ readonly patch?: unknown;
142
+ readonly candidateId?: string;
143
+ readonly importResultId?: string;
144
+ readonly patchId?: string;
145
+ readonly language?: FrontierSourceLanguage | string;
146
+ readonly sourcePath?: string;
147
+ readonly sourceHash?: string;
148
+ readonly sourceHashes?: readonly string[] | string;
149
+ readonly baseHash?: string;
150
+ readonly targetHash?: string;
151
+ readonly readiness?: SemanticMergeReadiness | string;
152
+ readonly projectionRisk?: SemanticMergeCandidateProjectionRisk | string;
153
+ readonly changedRegions?: readonly unknown[] | unknown;
154
+ readonly conflictKeys?: readonly string[] | string;
155
+ readonly evidence?: readonly EvidenceRecord[] | EvidenceRecord;
156
+ readonly evidenceIds?: readonly string[] | string;
157
+ readonly proofIds?: readonly string[] | string;
158
+ readonly reasonCodes?: readonly string[] | string;
159
+ readonly metadata?: Record<string, unknown>;
160
+ }
161
+
162
+ export type SemanticMergeCandidateWithAdmission = SemanticMergeCandidateRecord & {
163
+ readonly changedSemanticRegions?: readonly SemanticMergeCandidateChangedRegion[];
164
+ readonly sourceHashes?: SemanticMergeCandidateAdmissionRecord['sourceHashes'];
165
+ readonly evidenceIds?: readonly string[];
166
+ readonly proofIds?: readonly string[];
167
+ readonly projectionRisk?: SemanticMergeCandidateProjectionRisk;
168
+ readonly readinessSortKey?: number;
169
+ readonly mergeAdmission?: SemanticMergeCandidateAdmissionRecord;
170
+ };
171
+
172
+ export interface SemanticMergeCandidateAdmissionOverlapQuery {
173
+ readonly id?: string | readonly string[];
174
+ readonly ids?: readonly string[];
175
+ readonly candidateId?: string | readonly string[];
176
+ readonly candidateIds?: readonly string[];
177
+ readonly recordId?: string | readonly string[];
178
+ readonly recordIds?: readonly string[];
179
+ readonly regionId?: string | readonly string[];
180
+ readonly regionIds?: readonly string[];
181
+ readonly regionKey?: string | readonly string[];
182
+ readonly regionKeys?: readonly string[];
183
+ readonly conflictKey?: string | readonly string[];
184
+ readonly conflictKeys?: readonly string[];
185
+ readonly sourcePath?: string | readonly string[];
186
+ readonly sourcePaths?: readonly string[];
187
+ readonly overlapKind?: string | readonly string[];
188
+ readonly overlapKinds?: readonly string[];
189
+ readonly readiness?: SemanticMergeReadiness | string | readonly string[];
190
+ readonly readinesses?: readonly string[];
191
+ readonly risk?: string | readonly string[];
192
+ readonly risks?: readonly string[];
193
+ }
194
+
195
+ export declare const SemanticMergeCandidateProjectionRisks: readonly SemanticMergeCandidateProjectionRisk[];
196
+ export declare function createSemanticMergeCandidateAdmissionRecord(input?: SemanticMergeCandidateAdmissionInput, options?: CreateSemanticMergeCandidateAdmissionRecordOptions): SemanticMergeCandidateAdmissionRecord;
197
+ export declare function decorateSemanticMergeCandidateForAdmission<T extends SemanticMergeCandidateRecord | Record<string, unknown>>(input?: T, options?: CreateSemanticMergeCandidateAdmissionRecordOptions): T & SemanticMergeCandidateWithAdmission;
198
+ export declare function querySemanticMergeCandidateAdmissionOverlaps(records: SemanticMergeCandidateAdmissionInput | readonly SemanticMergeCandidateAdmissionInput[], query?: SemanticMergeCandidateAdmissionOverlapQuery): readonly SemanticMergeCandidateOverlapRecord[];
199
+ export declare function semanticMergeCandidateReadinessSortKey(candidateOrRecord: Partial<SemanticMergeCandidateAdmissionRecord> | Partial<SemanticMergeCandidateWithAdmission>): number;
200
+ export declare function sortSemanticMergeCandidateAdmissionRecords<T extends SemanticMergeCandidateAdmissionInput>(records: readonly T[], options?: { readonly desc?: boolean }): readonly SemanticMergeCandidateAdmissionRecord[];
@@ -3,6 +3,11 @@ import type {
3
3
  SemanticMergeCandidateRecord,
4
4
  SemanticMergeReadiness
5
5
  } from '@shapeshift-labs/frontier-lang-kernel';
6
+ import type {
7
+ SemanticMergeCandidateAdmissionRecord,
8
+ SemanticMergeCandidateChangedRegion,
9
+ SemanticMergeCandidateProjectionRisk
10
+ } from './semantic-merge-candidates.js';
6
11
 
7
12
  export type SemanticMergeConflictClass =
8
13
  | 'same-symbol-edit'
@@ -45,6 +50,13 @@ export interface SemanticMergeConflictSummary {
45
50
  }
46
51
 
47
52
  export type SemanticMergeCandidateWithConflicts = SemanticMergeCandidateRecord & {
53
+ readonly changedSemanticRegions?: readonly SemanticMergeCandidateChangedRegion[];
54
+ readonly sourceHashes?: SemanticMergeCandidateAdmissionRecord['sourceHashes'];
55
+ readonly evidenceIds?: readonly string[];
56
+ readonly proofIds?: readonly string[];
57
+ readonly projectionRisk?: SemanticMergeCandidateProjectionRisk;
58
+ readonly readinessSortKey?: number;
59
+ readonly mergeAdmission?: SemanticMergeCandidateAdmissionRecord;
48
60
  readonly conflictClasses?: readonly SemanticMergeConflictClassRecord[];
49
61
  readonly conflictSummary?: SemanticMergeConflictSummary;
50
62
  readonly metadata?: SemanticMergeCandidateRecord['metadata'] & {
@@ -25,6 +25,7 @@ import type {
25
25
  UniversalAstLayerRecord
26
26
  } from '@shapeshift-labs/frontier-lang-kernel';
27
27
  import type { SemanticImportSidecarAdmission, SemanticImportSidecarQuality } from './semantic-sidecar-admission.js';
28
+ import type { SemanticMergeCandidateAdmissionRecord, SemanticMergeCandidateProjectionRisk } from './semantic-merge-candidates.js';
28
29
  import type { SemanticMergeConflictClass, SemanticMergeConflictSummary } from './semantic-merge-conflicts.js';
29
30
  import type { SemanticImportImpactSummary } from './semantic-impact.js';
30
31
  import type { Diagnostic } from '@shapeshift-labs/frontier-lang-checker';
@@ -274,6 +275,12 @@ export interface SemanticImportSidecar {
274
275
  readonly reasons: readonly string[];
275
276
  readonly conflictClasses?: readonly SemanticMergeConflictClass[];
276
277
  readonly conflictSummary?: SemanticMergeConflictSummary;
278
+ readonly changedSemanticRegions?: number;
279
+ readonly sourceHashes?: SemanticMergeCandidateAdmissionRecord['sourceHashes'];
280
+ readonly evidenceIds?: readonly string[];
281
+ readonly projectionRisk?: SemanticMergeCandidateProjectionRisk;
282
+ readonly readinessSortKey?: number;
283
+ readonly overlapSummary?: SemanticMergeCandidateAdmissionRecord['overlapSummary'];
277
284
  readonly risk?: string;
278
285
  readonly operationCount: number;
279
286
  }[];
@@ -309,7 +316,5 @@ export interface SemanticImportSidecar {
309
316
  readonly semanticImportExpected: boolean; readonly semanticImportExpectedSatisfied: boolean; readonly semanticImportExpectedMissingReasonCodes: readonly string[];
310
317
  readonly readiness: SemanticMergeReadiness; readonly emptySemanticIndex: boolean;
311
318
  };
312
- readonly metadata?: Record<string, unknown>;
313
- }
314
-
319
+ readonly metadata?: Record<string, unknown>; }
315
320
  export interface SemanticImportSidecarOptions { readonly id?: string; readonly generatedAt?: number; readonly regionPrefix?: string; readonly targetPath?: string; readonly expected?: boolean; readonly semanticImportExpected?: boolean; readonly metadata?: Record<string, unknown>; }
package/dist/index.d.ts CHANGED
@@ -13,6 +13,7 @@ export * from './declarations/language-adapter-package-contracts.js';
13
13
  export * from './declarations/native-import-contracts.js';
14
14
  export * from './declarations/source-preservation.js';
15
15
  export * from './declarations/semantic-sidecar-admission.js';
16
+ export * from './declarations/semantic-merge-candidates.js';
16
17
  export * from './declarations/semantic-merge-conflicts.js';
17
18
  export * from './declarations/semantic-history.js';
18
19
  export * from './declarations/semantic-patch-bundle.js';
package/dist/index.js CHANGED
@@ -64,6 +64,7 @@ export { projectNativeImportToSource } from './internal/index-impl/projectNative
64
64
  export { queryNativeParserFeatureMatrix } from './internal/index-impl/queryNativeParserFeatureMatrix.js';
65
65
  export { queryProjectionReadinessMatrix } from './internal/index-impl/queryProjectionReadinessMatrix.js';
66
66
  export { createSemanticPatchBundleRecord, querySemanticPatchBundleRecords, SemanticPatchBundleAdmissionStatuses } from './internal/index-impl/semanticPatchBundleRecords.js';
67
+ export { createSemanticMergeCandidateAdmissionRecord, decorateSemanticMergeCandidateForAdmission, querySemanticMergeCandidateAdmissionOverlaps, SemanticMergeCandidateProjectionRisks, semanticMergeCandidateReadinessSortKey, sortSemanticMergeCandidateAdmissionRecords } from './internal/index-impl/semanticMergeCandidateRecords.js';
67
68
  export { querySemanticMergeConflictClasses, SemanticMergeConflictClasses, semanticMergeConflictRiskScore, sortSemanticMergeCandidatesByConflictRisk, summarizeSemanticMergeConflicts } from './internal/index-impl/semanticMergeConflicts.js';
68
69
  export { queryUniversalConversionPlan } from './internal/index-impl/queryUniversalConversionPlan.js';
69
70
  export { createSemanticHistoryRecord, querySemanticHistoryRecordOverlaps, SemanticHistoryAdmissionStatuses, SemanticHistoryConflictReasons, SemanticHistoryOverlapKinds, SemanticHistoryReviewerStatuses, semanticHistoryRecordsConflict, semanticHistoryRecordsOverlap } from './internal/index-impl/semanticHistoryRecords.js';
@@ -1,7 +1,9 @@
1
- import{idFragment}from'../../native-import-utils.js';import{semanticRegionKindForSymbol,semanticRegionMergePolicy}from'../../semantic-import-regions.js';
1
+ import{idFragment,uniqueRecordsById}from'../../native-import-utils.js';import{semanticRegionKindForSymbol,semanticRegionMergePolicy}from'../../semantic-import-regions.js';
2
2
  import{externalRelationPredicateForOccurrence}from'./externalRelationPredicateForOccurrence.js';
3
3
  export function attachExternalOwnership(result, context) {
4
4
  const occurrencesBySymbol = new Map();
5
+ const documentsById = new Map((result.documents ?? []).map((document) => [document.id, document]));
6
+ const ownershipRegions = [];
5
7
  for (const occurrence of result.occurrences) {
6
8
  if (!occurrencesBySymbol.has(occurrence.symbolId)) occurrencesBySymbol.set(occurrence.symbolId, []);
7
9
  occurrencesBySymbol.get(occurrence.symbolId).push(occurrence);
@@ -21,24 +23,28 @@ export function attachExternalOwnership(result, context) {
21
23
  result.symbols = result.symbols.map((symbol) => {
22
24
  const occurrences = occurrencesBySymbol.get(symbol.id) ?? [];
23
25
  const definition = occurrences.find((occurrence) => occurrence.role === 'definition') ?? occurrences[0];
26
+ const document = documentsById.get(definition?.documentId);
24
27
  const sourceSpan = symbol.definitionSpan ?? definition?.span;
25
28
  const regionKind = semanticRegionKindForSymbol(symbol, undefined, undefined);
29
+ const sourcePath = sourceSpan?.path ?? document?.path ?? context.sourcePath;
30
+ const language = symbol.language ?? document?.language ?? context.language;
31
+ const normalizedRegionKind = symbol.metadata?.ownershipRegionKind ?? regionKind;
26
32
  const key = [
27
33
  'external',
28
- symbol.language ?? context.language ?? 'unknown',
29
- sourceSpan?.path ?? context.sourcePath ?? 'memory',
30
- regionKind,
34
+ language ?? 'unknown',
35
+ sourcePath ?? 'memory',
36
+ normalizedRegionKind,
31
37
  symbol.name ?? symbol.id
32
38
  ].join('#');
33
39
  const region = {
34
- id: `region_${idFragment(key)}`,
35
- key,
36
- regionKind,
40
+ id: symbol.metadata?.ownershipRegionId ?? `region_${idFragment(key)}`,
41
+ key: symbol.metadata?.ownershipRegionKey ?? key,
42
+ regionKind: normalizedRegionKind,
37
43
  granularity: 'symbol',
38
- language: symbol.language ?? context.language,
44
+ language,
39
45
  documentId: definition?.documentId,
40
- sourcePath: sourceSpan?.path ?? context.sourcePath,
41
- sourceHash: context.sourceHash,
46
+ sourcePath,
47
+ sourceHash: sourceSpan?.sourceId ?? document?.sourceHash ?? context.sourceHash,
42
48
  symbolId: symbol.id,
43
49
  symbolName: symbol.name,
44
50
  symbolKind: symbol.kind,
@@ -50,6 +56,7 @@ export function attachExternalOwnership(result, context) {
50
56
  source: 'external-semantic-index'
51
57
  }
52
58
  };
59
+ ownershipRegions.push(region);
53
60
  result.facts.push({
54
61
  id: `fact_${idFragment(symbol.id)}_ownership_region`,
55
62
  predicate: 'semanticOwnershipRegion',
@@ -76,4 +83,5 @@ export function attachExternalOwnership(result, context) {
76
83
  }
77
84
  };
78
85
  });
86
+ result.ownershipRegions = uniqueRecordsById([...(result.ownershipRegions ?? []), ...ownershipRegions]);
79
87
  }
@@ -84,6 +84,12 @@ export function createSemanticImportSidecar(importResult, options = {}) {
84
84
  reasons: candidate.reasons ?? [],
85
85
  conflictClasses: (candidate.conflictClasses ?? candidate.metadata?.conflictClasses ?? []).map((record) => record.class).filter(Boolean),
86
86
  conflictSummary: candidate.conflictSummary ?? candidate.metadata?.conflictSummary,
87
+ changedSemanticRegions: candidate.changedSemanticRegions?.length ?? candidate.mergeAdmission?.changedSemanticRegions?.length ?? 0,
88
+ sourceHashes: candidate.sourceHashes ?? candidate.mergeAdmission?.sourceHashes,
89
+ evidenceIds: candidate.evidenceIds ?? candidate.mergeAdmission?.evidenceIds ?? [],
90
+ projectionRisk: candidate.projectionRisk ?? candidate.mergeAdmission?.projectionRisk,
91
+ readinessSortKey: candidate.readinessSortKey ?? candidate.mergeAdmission?.readinessSortKey,
92
+ overlapSummary: candidate.mergeAdmission?.overlapSummary,
87
93
  risk: candidate.risk,
88
94
  operationCount: candidate.operations?.length ?? candidate.patch?.operations?.length ?? 0
89
95
  })),
@@ -1,5 +1,6 @@
1
1
  import{idFragment,uniqueStrings}from'../../native-import-utils.js';import{createSemanticMergeCandidateRecord}from'@shapeshift-labs/frontier-lang-kernel';
2
2
  import{createSemanticImportSidecar}from'./createSemanticImportSidecar.js';import{nativeNodeId}from'./nativeNodeId.js';import{readStringArray}from'./readStringArray.js';import{selectSemanticSliceRecords}from'./selectSemanticSliceRecords.js';import{semanticSliceContext}from'./semanticSliceContext.js';import{semanticSliceExpectedAssertions}from'./semanticSliceExpectedAssertions.js';import{semanticSliceReadiness}from'./semanticSliceReadiness.js';import{semanticSliceReasons}from'./semanticSliceReasons.js';import{semanticSliceRecords}from'./semanticSliceRecords.js';import{semanticSliceSourceFiles}from'./semanticSliceSourceFiles.js';import{semanticSliceSourceMapLinks}from'./semanticSliceSourceMapLinks.js';import{semanticSliceSourceSpans}from'./semanticSliceSourceSpans.js';import{semanticSliceTouchedSymbol}from'./semanticSliceTouchedSymbol.js';
3
+ import{decorateSemanticMergeCandidateForAdmission}from'./semanticMergeCandidateRecords.js';
3
4
  export function createSemanticSlice(input, options = {}) {
4
5
  const context = semanticSliceContext(input, options);
5
6
  const sidecar = context.sidecar ?? (context.importResult ? createSemanticImportSidecar(context.importResult, {
@@ -50,7 +51,7 @@ export function createSemanticSlice(input, options = {}) {
50
51
  sidecarId: sidecar?.id
51
52
  }
52
53
  }];
53
- const mergeCandidate = createSemanticMergeCandidateRecord({
54
+ const mergeCandidate = decorateSemanticMergeCandidateForAdmission(createSemanticMergeCandidateRecord({
54
55
  id: options.mergeCandidateId ?? `merge_candidate_${idPart}_semantic_slice`,
55
56
  importResultId: context.importResult?.id,
56
57
  language: context.language,
@@ -70,7 +71,7 @@ export function createSemanticSlice(input, options = {}) {
70
71
  dependencyRelationIds: selection.relations.map((relation) => relation.id).filter(Boolean),
71
72
  autoMergeClaim: false
72
73
  }
73
- });
74
+ }),{evidence,sourceHash:sourceFiles[0]?.sourceHash,metadata:{source:'createSemanticSlice'}});
74
75
  return {
75
76
  kind: 'frontier.lang.semanticSlice',
76
77
  version: 1,
@@ -1,5 +1,6 @@
1
1
  import{idFragment,maxSemanticMergeReadiness,uniqueByLossId,uniqueRecordsById,uniqueStrings}from'../../native-import-utils.js';import{createPatch,createSemanticMergeCandidateRecord}from'@shapeshift-labs/frontier-lang-kernel';
2
2
  import{attachNativeChangeRegionProjectionMetadata}from'./attachNativeChangeRegionProjectionMetadata.js';import{classifyNativeSourceMergeConflicts}from'./semanticMergeConflicts.js';import{createSemanticImportSidecar}from'./createSemanticImportSidecar.js';import{diffNativeOwnershipRegions}from'./diffNativeOwnershipRegions.js';import{diffNativeSymbols}from'./diffNativeSymbols.js';import{fileLevelNativeChangeRegion}from'./fileLevelNativeChangeRegion.js';import{mapDiffSymbols}from'./mapDiffSymbols.js';import{nativeChangeSpans}from'./nativeChangeSpans.js';import{nativeChangeTouchedSymbol}from'./nativeChangeTouchedSymbol.js';import{nativeImportReadiness}from'./nativeImportReadiness.js';import{nativeSourceChangeReasons}from'./nativeSourceChangeReasons.js';import{nativeSourceChangeSummary}from'./nativeSourceChangeSummary.js';import{normalizeNativeDiffImport}from'./normalizeNativeDiffImport.js';import{summarizeNativeChangedRegionProjections}from'./summarizeNativeChangedRegionProjections.js';
3
+ import{decorateSemanticMergeCandidateForAdmission}from'./semanticMergeCandidateRecords.js';
3
4
  export function diffNativeSourceImports(input) {
4
5
  const before = normalizeNativeDiffImport(input.before, input, 'before');
5
6
  const after = normalizeNativeDiffImport(input.after, input, 'after');
@@ -104,7 +105,7 @@ export function diffNativeSourceImports(input) {
104
105
  semanticMergeConflictSummary: mergeConflictProfile.conflictSummary
105
106
  }
106
107
  });
107
- const mergeCandidate = createSemanticMergeCandidateRecord({
108
+ const mergeCandidate = decorateSemanticMergeCandidateForAdmission(createSemanticMergeCandidateRecord({
108
109
  id: input.mergeCandidateId ?? `merge_candidate_${idPart}_native_source_diff`,
109
110
  importResultId: after?.id ?? before?.id,
110
111
  patchId: patch.id,
@@ -131,7 +132,7 @@ export function diffNativeSourceImports(input) {
131
132
  conflictClasses: mergeConflictProfile.conflictClasses,
132
133
  conflictSummary: mergeConflictProfile.conflictSummary
133
134
  }
134
- });
135
+ }),{changedRegions,evidence,patch,baseHash:beforeHash,targetHash:afterHash,metadata:{source:'diffNativeSourceImports'}});
135
136
  return {
136
137
  kind: 'frontier.lang.nativeSourceChangeSet',
137
138
  version: 1,
@@ -7,6 +7,7 @@ export function externalSemanticBase(context, metadata = {}) {
7
7
  occurrences: [],
8
8
  relations: [],
9
9
  facts: [],
10
+ ownershipRegions: [],
10
11
  evidence: [externalSemanticEvidence(context, 'passed', `Imported ${context.format} semantic index payload.`)],
11
12
  losses: [externalSemanticCoverageLoss(context)],
12
13
  semanticStatus: 'external-semantic-index',
@@ -18,6 +18,7 @@ export function importExternalSemanticIndex(input) {
18
18
  metadata: input?.metadata ?? {}
19
19
  };
20
20
  const normalized = normalizeExternalSemanticIndexPayload(payload, context);
21
+ const ownershipRegions = normalized.ownershipRegions ?? [];
21
22
  const evidence = attachNativeImportLossSummary(
22
23
  uniqueByEvidenceId([...(normalized.evidence ?? []), ...(input?.evidence ?? [])]),
23
24
  summarizeNativeImportLosses(normalized.losses ?? [], {
@@ -116,6 +117,7 @@ export function importExternalSemanticIndex(input) {
116
117
  semanticIndex,
117
118
  universalAst,
118
119
  sourceMaps,
120
+ ownershipRegions,
119
121
  losses,
120
122
  evidence,
121
123
  readiness,
@@ -125,6 +127,8 @@ export function importExternalSemanticIndex(input) {
125
127
  occurrences: semanticIndex.occurrences.length,
126
128
  relations: semanticIndex.relations.length,
127
129
  facts: semanticIndex.facts.length,
130
+ ownershipRegions: ownershipRegions.length,
131
+ ownershipRegionKinds: [...new Set(ownershipRegions.map((region) => region.regionKind).filter(Boolean))],
128
132
  sourceMapMappings: sourceMaps.reduce((sum, sourceMap) => sum + (sourceMap.mappings?.length ?? 0), 0),
129
133
  losses: losses.length,
130
134
  readiness: readiness.readiness
@@ -1,4 +1,5 @@
1
1
  import{countBy,maxSemanticMergeReadiness,uniqueRecordsById,uniqueStrings}from'../../native-import-utils.js';
2
+ import{createSemanticMergeCandidateAdmissionRecord,querySemanticMergeCandidateAdmissionOverlaps,sortSemanticMergeCandidateAdmissionRecords}from'./semanticMergeCandidateRecords.js';
2
3
 
3
4
  const riskRank=Object.freeze({low:0,medium:1,unknown:2,high:3});
4
5
  const preservationRank=Object.freeze({exact:0,lossy:1,missing:2,stale:3,empty:4});
@@ -155,21 +156,45 @@ export function admissionMergeCandidates(projectResult,imports,mergeCandidates,l
155
156
  projectResult?.patch,
156
157
  ...imports.map((imported)=>imported?.patch)
157
158
  ].filter((patch)=>patch?.id).map((patch)=>[patch.id,patch]));
158
- const risks=mergeCandidates.map((candidate)=>candidateRisk(candidate,patchById.get(candidate.patchId)));
159
+ const records=sortSemanticMergeCandidateAdmissionRecords(mergeCandidates.map((candidate)=>createSemanticMergeCandidateAdmissionRecord(candidate,{patch:patchById.get(candidate.patchId)})));
160
+ const recordByCandidateId=new Map(records.map((record)=>[record.candidateId,record]));
161
+ const overlaps=querySemanticMergeCandidateAdmissionOverlaps(records);
162
+ const risks=mergeCandidates.map((candidate)=>{
163
+ const record=recordByCandidateId.get(candidate.id);
164
+ return maxRisk(candidateRisk(candidate,patchById.get(candidate.patchId)),record?.projectionRisk??'low');
165
+ });
159
166
  const readiness=mergeCandidates.reduce(
160
- (current,candidate)=>maxSemanticMergeReadiness(current,candidate.readiness),
167
+ (current,candidate)=>maxSemanticMergeReadiness(current,recordByCandidateId.get(candidate.id)?.readiness??candidate.readiness),
161
168
  lossSummary?.semanticMergeReadiness??'ready'
162
169
  );
170
+ const overlapCandidateIds=uniqueStrings(overlaps.flatMap((overlap)=>overlap.candidateIds??[]));
163
171
  return {
164
172
  total:mergeCandidates.length,
165
173
  readiness,
166
174
  highestRisk:risks.reduce(maxRisk,'low'),
175
+ projectionRisk:records.reduce((current,record)=>maxRisk(current,record.projectionRisk??'unknown'),'low'),
167
176
  byRisk:countBy(risks),
168
- byReadiness:countBy(mergeCandidates.map((candidate)=>candidate.readiness??'needs-review')),
177
+ byReadiness:countBy(records.map((record)=>record.readiness??'needs-review')),
178
+ byProjectionRisk:countBy(records.map((record)=>record.projectionRisk??'unknown')),
169
179
  highRiskCandidateIds:mergeCandidates.filter((candidate,index)=>risks[index]==='high').map((candidate)=>candidate.id).filter(Boolean),
170
- reviewCandidateIds:mergeCandidates.filter((candidate)=>candidate.readiness==='needs-review').map((candidate)=>candidate.id).filter(Boolean),
171
- blockedCandidateIds:mergeCandidates.filter((candidate)=>candidate.readiness==='blocked').map((candidate)=>candidate.id).filter(Boolean),
172
- conflictKeys:uniqueStrings(mergeCandidates.flatMap((candidate)=>candidate.conflictKeys??[])),
180
+ reviewCandidateIds:records.filter((record)=>record.readiness==='needs-review'||record.admission.reviewRequired).map((record)=>record.candidateId).filter(Boolean),
181
+ blockedCandidateIds:records.filter((record)=>record.readiness==='blocked'||record.admission.action==='block').map((record)=>record.candidateId).filter(Boolean),
182
+ highProjectionRiskCandidateIds:records.filter((record)=>record.projectionRisk==='high').map((record)=>record.candidateId).filter(Boolean),
183
+ conflictKeys:uniqueStrings(records.flatMap((record)=>record.conflictKeys??[])),
184
+ readinessOrderCandidateIds:records.map((record)=>record.candidateId).filter(Boolean),
185
+ changedSemanticRegions:{
186
+ total:records.reduce((sum,record)=>sum+record.changedSemanticRegions.length,0),
187
+ byKind:countBy(records.flatMap((record)=>record.changedSemanticRegions.map((region)=>region.regionKind??'unknown'))),
188
+ conflictKeys:uniqueStrings(records.flatMap((record)=>record.changedSemanticRegions.map((region)=>region.conflictKey)))
189
+ },
190
+ overlaps:{
191
+ total:overlaps.length,
192
+ candidateIds:overlapCandidateIds,
193
+ conflictKeys:uniqueStrings(overlaps.flatMap((overlap)=>overlap.conflictKeys??[])),
194
+ sourcePaths:uniqueStrings(overlaps.map((overlap)=>overlap.sourcePath).filter(Boolean)),
195
+ pairs:overlaps
196
+ },
197
+ records,
173
198
  patchRisk:normalizeRisk(projectResult?.patch?.risk)
174
199
  };
175
200
  }
@@ -71,7 +71,7 @@ export async function runNativeImporterAdapter(adapter, input = {}) {
71
71
  sourcePath: parseResult.sourcePath ?? input.sourcePath,
72
72
  sourceHash: parseResult.sourceHash ?? sourceHash
73
73
  });
74
- const evidence = [...(parseResult.evidence ?? []), sourceEvidence];
74
+ const evidence = [...(input.evidence ?? []), ...(parseResult.evidence ?? []), sourceEvidence];
75
75
  const importInput = {
76
76
  ...input,
77
77
  ...parseResult,