@shapeshift-labs/frontier-lang-compiler 0.2.47 → 0.2.49

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -129,6 +129,8 @@ import {
129
129
  createNativeParserAstFormatMatrix,
130
130
  createProjectionTargetLossMatrix,
131
131
  createUniversalCapabilityMatrix,
132
+ createUniversalConversionPlan,
133
+ queryUniversalConversionPlan,
132
134
  importNativeSource
133
135
  } from '@shapeshift-labs/frontier-lang-compiler';
134
136
 
@@ -162,6 +164,20 @@ const pythonUniversal = universalMatrix.languages.find((entry) => entry.language
162
164
 
163
165
  console.log(pythonUniversal.readiness); // combined import/parser/projection readiness
164
166
  console.log(pythonUniversal.blockers); // missing evidence/adapters that prevent merge admission
167
+
168
+ const conversionPlan = createUniversalConversionPlan({
169
+ imports: [imported],
170
+ targets: ['python', 'rust'],
171
+ requiredFeatures: ['syntax', 'semantic', 'sourcePreservation']
172
+ });
173
+ const pythonToRust = queryUniversalConversionPlan(conversionPlan, {
174
+ sourceLanguage: 'python',
175
+ target: 'rust'
176
+ }).bestRoute;
177
+
178
+ console.log(pythonToRust.mode); // "semantic-index-only", "target-adapter", "stub-only", etc.
179
+ console.log(pythonToRust.missingEvidence); // adapter/proof/source-map gaps for swarm workers
180
+ console.log(pythonToRust.mergeScore.value); // sortable merge-review score, not a proof
165
181
  ```
166
182
 
167
183
  The projection target matrix separates five runtime/API classes:
@@ -174,6 +190,8 @@ The projection target matrix separates five runtime/API classes:
174
190
 
175
191
  `createUniversalCapabilityMatrix` composes the import coverage, parser AST format, parser feature, and projection target matrices into a single language row per source language. It is the coordinator-facing view for universal-language work: it shows imports, symbols, source-map mappings, parser feature readiness, projection targets, missing adapters, unsupported target features, blockers, and review reasons without claiming lossless conversion where evidence is absent.
176
192
 
193
+ `createUniversalConversionPlan` turns that capability evidence into coordinator tasks: preserve exact source, run a target adapter, emit stubs, attach semantic-index evidence, or block the route until missing parser/adapter/proof evidence exists. Every route carries `autoMergeClaim: false`, `semanticEquivalenceClaim: false`, missing evidence, task hints, and a `frontier.lang.semanticMergeScore.v1` score for swarm merge admission.
194
+
177
195
  Preserve exact native source text, token/trivia hashes, comments, whitespace, and source directives as evidence. This does not claim full semantic understanding; it keeps round-trip material available while exact parser adapters catch up:
178
196
 
179
197
  ```js
@@ -333,6 +351,7 @@ Extract a surgical semantic slice when a worker only needs one symbol, region, n
333
351
 
334
352
  ```js
335
353
  import {
354
+ createSemanticSliceAdmissionRecord,
336
355
  createSemanticSlice,
337
356
  importNativeSource,
338
357
  testSemanticSlice,
@@ -362,11 +381,16 @@ const gate = testSemanticSlice(slice, {
362
381
  });
363
382
 
364
383
  console.log(gate.status); // "passed", "needs-review", or "failed"
384
+ const admission = createSemanticSliceAdmissionRecord(slice, { testResult: gate });
385
+ console.log(admission.mergeScore.value); // sortable 0-100 semantic merge score
386
+ console.log(admission.autoMergeClaim); // always false
365
387
  console.log(writeSemanticSliceJson(slice)); // stable JSON for worker inputs
366
388
  ```
367
389
 
368
390
  A semantic slice is the small unit a swarm can hand to a worker instead of copying a full repository. It carries the selected symbols, ownership regions, native nodes, relations, occurrences, source-map links, source spans, source excerpts, source hashes, focused verification commands, fixture hints, and merge-admission metadata. It does not claim the patch is correct; it makes the context and conflicts machine-readable so admission scoring can combine changed ownership, focused test status, stale/source-hash checks, evidence, and semantic risk in one sortable record.
369
391
 
392
+ Slice admission records add a compact `frontier.lang.semanticMergeScore.v1` score with semantic-selection, source-freshness, ownership-isolation, verification-evidence, and review-risk components. They are built for coordinator queues and dashboards: sort likely useful slices first, reject stale or empty slices early, and keep correctness proof separate from merge metadata.
393
+
370
394
  Compile native source imports through the same reader/IR/writer facade that swarms use for sidecar evidence. Same-language targets preserve exact source when hashes match; cross-language targets emit declaration stubs until a real adapter provides stronger evidence:
371
395
 
372
396
  ```js
@@ -4,6 +4,8 @@ import {
4
4
  createNativeSourcePreservation,
5
5
  createSemanticImportSidecar,
6
6
  createSemanticSlice,
7
+ createSemanticSliceAdmissionRecord,
8
+ createUniversalConversionPlan,
7
9
  projectNativeImportToSource,
8
10
  summarizeNativeImportFeatureEvidence,
9
11
  testSemanticSlice
@@ -40,6 +42,18 @@ export function measureNativeTransformations(nativeImportResults) {
40
42
  const semanticSliceGates = semanticSlices.map((slice) => testSemanticSlice(slice, { requireSourceMapLinks: false }));
41
43
  const sliceGateDurationMs = performance.now() - sliceGateStart;
42
44
  const sliceGateFailures = semanticSliceGates.filter((gate) => gate.status === 'failed').length;
45
+ const sliceAdmissionStart = performance.now();
46
+ const semanticSliceAdmissions = semanticSlices.map((slice, index) => createSemanticSliceAdmissionRecord(slice, {
47
+ testResult: semanticSliceGates[index]
48
+ }));
49
+ const sliceAdmissionDurationMs = performance.now() - sliceAdmissionStart;
50
+
51
+ const conversionPlanStart = performance.now();
52
+ const conversionPlan = createUniversalConversionPlan({
53
+ imports: nativeImportResults.slice(0, 100),
54
+ targets: ['javascript', 'rust', 'python']
55
+ });
56
+ const conversionPlanDurationMs = performance.now() - conversionPlanStart;
43
57
 
44
58
  const featureEvidenceStart = performance.now();
45
59
  const featureEvidenceSummaries = nativeImportResults.map((imported) => summarizeNativeImportFeatureEvidence(imported.losses, {
@@ -65,9 +79,15 @@ export function measureNativeTransformations(nativeImportResults) {
65
79
  semanticSlices: semanticSlices.length,
66
80
  sliceDurationMs,
67
81
  sliceGateDurationMs,
82
+ sliceAdmissionDurationMs,
68
83
  sliceSourceMapLinks,
69
84
  sliceConflictKeys,
70
85
  sliceGateFailures,
86
+ sliceAdmissions: semanticSliceAdmissions.length,
87
+ sliceAdmissionRejected: semanticSliceAdmissions.filter((admission) => admission.action === 'reject').length,
88
+ conversionPlanRoutes: conversionPlan.routes.length,
89
+ conversionPlanBlocked: conversionPlan.summary.blockedRoutes,
90
+ conversionPlanDurationMs,
71
91
  featureEvidencePolicyMatches,
72
92
  featureEvidenceDurationMs,
73
93
  nativeProjections: nativeProjections.length,
package/bench/smoke.mjs CHANGED
@@ -51,9 +51,15 @@ console.log(JSON.stringify({
51
51
  semanticSlices: transformMetrics.semanticSlices,
52
52
  sliceDurationMs: Number(transformMetrics.sliceDurationMs.toFixed(2)),
53
53
  sliceGateDurationMs: Number(transformMetrics.sliceGateDurationMs.toFixed(2)),
54
+ sliceAdmissionDurationMs: Number(transformMetrics.sliceAdmissionDurationMs.toFixed(2)),
54
55
  sliceSourceMapLinks: transformMetrics.sliceSourceMapLinks,
55
56
  sliceConflictKeys: transformMetrics.sliceConflictKeys,
56
57
  sliceGateFailures: transformMetrics.sliceGateFailures,
58
+ sliceAdmissions: transformMetrics.sliceAdmissions,
59
+ sliceAdmissionRejected: transformMetrics.sliceAdmissionRejected,
60
+ conversionPlanRoutes: transformMetrics.conversionPlanRoutes,
61
+ conversionPlanBlocked: transformMetrics.conversionPlanBlocked,
62
+ conversionPlanDurationMs: Number(transformMetrics.conversionPlanDurationMs.toFixed(2)),
57
63
  featureEvidencePolicyMatches: transformMetrics.featureEvidencePolicyMatches,
58
64
  featureEvidenceDurationMs: Number(transformMetrics.featureEvidenceDurationMs.toFixed(2)),
59
65
  nativeProjections: transformMetrics.nativeProjections,
@@ -37,12 +37,14 @@ import type { NativeParserFeatureCategory, NativeParserFeatureCoverageStatus, Na
37
37
  import type { NativeImportCoverageLanguage, NativeImportCoverageMatrix, NativeImportCoverageMatrixOptions } from './native-import-coverage.js';
38
38
  import type { ProjectionTargetLossClass, ProjectionSourceProjectionCoverage, ProjectionTargetCoverageEntry, ProjectionTargetLanguageCoverage, ProjectionTargetLossMatrix, ProjectionTargetLossMatrixOptions } from './projection-coverage.js';
39
39
  import type { UniversalCapabilityLanguageRow, UniversalCapabilityMatrix, UniversalCapabilityMatrixOptions } from './universal-capability.js';
40
+ import type { UniversalConversionPlan, UniversalConversionPlanOptions, UniversalConversionPlanQuery, UniversalConversionPlanQueryResult } from './universal-conversion-plan.js';
40
41
  import type { UniversalDialectRegistry, UniversalDialectRegistryInput, UniversalDialectRecordInput, UniversalExternRecordInput } from './universal-dialects.js';
41
42
  import type { NativeImportContractSource, NativeImportSourcePreservationRecordSummary, NativeImportSourcePreservationContract, NativeImportAdapterCoverageRecordSummary, NativeImportAdapterCoverageContract, NativeImportRegionSummary, NativeImportSourceMapSummary, NativeImportReadinessContract, NativeImportResultContract, NativeImportResultContractOptions } from './native-import-contracts.js';
42
43
  import type { NativeSourceTokenKind, NativeSourcePreservedToken, NativeSourcePreservedDirective, NativeSourcePreservation, CreateNativeSourcePreservationOptions } from './source-preservation.js';
43
44
  import type { SemanticImportOwnershipRegion, SemanticImportSidecarSymbol, SemanticImportRegionTaxonomySummary, SemanticImportPatchHint, SemanticImportSidecarImportEntry, SemanticImportSidecarSourcePreservationRecord, SemanticImportSidecarUniversalAstLayerSummary, SemanticImportSidecarProofSpecSummary, SemanticImportSidecarParadigmSemanticsSummary, SemanticImportSidecar, SemanticImportSidecarOptions } from './semantic-sidecar.js';
44
45
  import type { NativeSourceChangeKind, NativeSourceChangeProjectionEndpoint, NativeSourceChangeProjectionSourceMapLink, NativeSourceChangeProjectionMetadata, NativeSourceChangeProjectionSummary, NativeSourceChangeSymbol, NativeSourceChangeRegion, NativeSourceChangeSummary, DiffNativeSourceImportsOptions, DiffNativeSourcesOptions, NativeSourceChangeSet } from './native-diff.js';
45
46
  import type { SemanticSliceInput, CreateSemanticSliceOptions, SemanticSliceSourceMapLink, SemanticSliceSourceFile, SemanticSliceExpectedAssertion, SemanticSlice, TestSemanticSliceOptions, SemanticSliceTestAssertion, SemanticSliceTestResult } from './semantic-slice.js';
47
+ import type { CreateSemanticSliceAdmissionRecordOptions, SemanticSliceAdmissionRecord } from './semantic-slice-admission.js';
46
48
  import type { NativeImporterAdapterExactness, NativeImporterAdapterSemanticCoverage, NativeImporterAdapterCoverageSnapshot, NativeImporterAdapterCoverageObserved, NativeImporterAdapterCoverageCapabilityRow, NativeImporterAdapterCoverageCapabilityEvidence, NativeImporterAdapterCoverageSummary, NativeImporterAdapterCoverageInput } from './adapter-coverage.js';
47
49
  import type { NativeImporterAdapterDiagnostic, ImportNativeSourceOptions, NativeSourceImportResult, ExternalSemanticIndexFormat, ImportExternalSemanticIndexOptions, ExternalSemanticIndexImportSummary, ExternalSemanticIndexImportResult, NativeImporterAdapterParseInput, NativeImporterAdapterParseResult, NativeImporterAdapter, NativeImporterAdapterSummary, RunNativeImporterAdapterOptions, NativeImporterAdapterImportResult } from './import-adapter-core.js';
48
50
  import type { JavaScriptNativeImporterAdapterOptions, TypeScriptCompilerNativeImporterAdapterOptions, PythonAstNativeImporterAdapterOptions, RustSynNativeImporterAdapterOptions, ClangAstNativeImporterAdapterOptions, GoAstNativeImporterAdapterOptions } from './import-adapter-options-native.js';
@@ -86,6 +88,11 @@ export declare function createNativeParserFeatureMatrix(options?: NativeParserFe
86
88
  export declare function queryNativeParserFeatureMatrix(matrixOrOptions?: NativeParserFeatureMatrix | NativeParserFeatureMatrixOptions, query?: NativeParserFeatureMatrixQuery): NativeParserFeatureMatrixQueryResult;
87
89
  export declare function createProjectionTargetLossMatrix(options?: ProjectionTargetLossMatrixOptions): ProjectionTargetLossMatrix;
88
90
  export declare function createUniversalCapabilityMatrix(options?: UniversalCapabilityMatrixOptions): UniversalCapabilityMatrix;
91
+ export declare function createUniversalConversionPlan(options?: UniversalConversionPlanOptions): UniversalConversionPlan;
92
+ export declare function queryUniversalConversionPlan(
93
+ planOrOptions?: UniversalConversionPlan | UniversalConversionPlanOptions,
94
+ query?: UniversalConversionPlanQuery
95
+ ): UniversalConversionPlanQueryResult;
89
96
  export declare function createNativeSourcePreservation(options: CreateNativeSourcePreservationOptions): NativeSourcePreservation;
90
97
  export declare function createSemanticImportSidecar(importResult: NativeSourceImportResult | NativeProjectImportResult, options?: SemanticImportSidecarOptions): SemanticImportSidecar;
91
98
  export declare function createNativeImportResultContract(importResult: NativeSourceImportResult | NativeProjectImportResult, options?: NativeImportResultContractOptions): NativeImportResultContract;
@@ -109,6 +116,7 @@ export declare function importNativeSource(input: ImportNativeSourceOptions): Na
109
116
  export declare function diffNativeSources(input: DiffNativeSourcesOptions): NativeSourceChangeSet;
110
117
  export declare function diffNativeSourceImports(input: DiffNativeSourceImportsOptions): NativeSourceChangeSet;
111
118
  export declare function createSemanticSlice(input: SemanticSliceInput, options?: CreateSemanticSliceOptions): SemanticSlice;
119
+ export declare function createSemanticSliceAdmissionRecord(slice: SemanticSlice, options?: CreateSemanticSliceAdmissionRecordOptions): SemanticSliceAdmissionRecord;
112
120
  export declare function testSemanticSlice(slice: SemanticSlice, options?: TestSemanticSliceOptions): SemanticSliceTestResult;
113
121
  export declare function readSemanticSliceJson(source: string): SemanticSlice;
114
122
  export declare function writeSemanticSliceJson(slice: SemanticSlice): string;
@@ -0,0 +1,82 @@
1
+ import type { EvidenceRecord, SemanticMergeReadiness } from '@shapeshift-labs/frontier-lang-kernel';
2
+ import type { SemanticSlice, SemanticSliceTestResult, TestSemanticSliceOptions } from './semantic-slice.js';
3
+
4
+ export type SemanticSliceAdmissionAction = 'admit' | 'prioritize' | 'reject';
5
+ export type SemanticSliceAdmissionPriority = 'low' | 'normal' | 'high' | 'blocker';
6
+ export type SemanticSliceAdmissionRisk = 'low' | 'medium' | 'high' | 'unknown';
7
+ export type SemanticSliceAdmissionScoreComponentKey =
8
+ | 'semanticSelection'
9
+ | 'sourceFreshness'
10
+ | 'ownershipIsolation'
11
+ | 'verificationEvidence'
12
+ | 'reviewRisk';
13
+ export type SemanticSliceAdmissionScoreComponentStatus = 'strong' | 'partial' | 'weak' | 'blocked';
14
+
15
+ export interface SemanticSliceAdmissionScoreComponent {
16
+ readonly key: SemanticSliceAdmissionScoreComponentKey;
17
+ readonly score: number;
18
+ readonly weight: number;
19
+ readonly weightedScore: number;
20
+ readonly status: SemanticSliceAdmissionScoreComponentStatus;
21
+ readonly reasons: readonly string[];
22
+ readonly signals: Record<string, unknown>;
23
+ }
24
+
25
+ export interface SemanticSliceAdmissionMergeScore {
26
+ readonly schema: 'frontier.lang.semanticMergeScore.v1';
27
+ readonly version: 1;
28
+ readonly value: number;
29
+ readonly uncappedValue: number;
30
+ readonly sortKey: number;
31
+ readonly higherIsBetter: true;
32
+ readonly readiness: SemanticMergeReadiness;
33
+ readonly risk: SemanticSliceAdmissionRisk;
34
+ readonly action: SemanticSliceAdmissionAction;
35
+ readonly components: Readonly<Record<SemanticSliceAdmissionScoreComponentKey, SemanticSliceAdmissionScoreComponent>>;
36
+ readonly penalties: readonly string[];
37
+ }
38
+
39
+ export interface SemanticSliceAdmissionRecord {
40
+ readonly kind: 'frontier.lang.semanticSliceAdmission';
41
+ readonly version: 1;
42
+ readonly id: string;
43
+ readonly generatedAt: number;
44
+ readonly sliceId?: string;
45
+ readonly importId?: string;
46
+ readonly sourcePath?: string;
47
+ readonly action: SemanticSliceAdmissionAction;
48
+ readonly priority: SemanticSliceAdmissionPriority;
49
+ readonly readiness: SemanticMergeReadiness;
50
+ readonly risk: SemanticSliceAdmissionRisk;
51
+ readonly autoMergeClaim: false;
52
+ readonly reviewRequired: boolean;
53
+ readonly mergeScore: SemanticSliceAdmissionMergeScore;
54
+ readonly counts: {
55
+ readonly symbols: number;
56
+ readonly ownershipRegions: number;
57
+ readonly nativeNodes: number;
58
+ readonly sourceMapLinks: number;
59
+ readonly sourceFiles: number;
60
+ readonly focusedCommands: number;
61
+ readonly fixtureHints: number;
62
+ readonly assertions: number;
63
+ readonly failedAssertions: number;
64
+ readonly warningAssertions: number;
65
+ };
66
+ readonly conflictKeys: readonly string[];
67
+ readonly ownershipKeys: readonly string[];
68
+ readonly sourceHashes: SemanticSlice['mergeAdmission']['sourceHashes'];
69
+ readonly testResult?: SemanticSliceTestResult;
70
+ readonly reasons: readonly string[];
71
+ readonly metadata: Record<string, unknown>;
72
+ }
73
+
74
+ export interface CreateSemanticSliceAdmissionRecordOptions extends TestSemanticSliceOptions {
75
+ readonly testResult?: SemanticSliceTestResult;
76
+ readonly evidence?: readonly EvidenceRecord[];
77
+ }
78
+
79
+ export declare function createSemanticSliceAdmissionRecord(
80
+ slice: SemanticSlice,
81
+ options?: CreateSemanticSliceAdmissionRecordOptions
82
+ ): SemanticSliceAdmissionRecord;
@@ -0,0 +1,203 @@
1
+ import type {
2
+ EvidenceRecord,
3
+ FrontierSourceLanguage,
4
+ SemanticMergeReadiness
5
+ } from '@shapeshift-labs/frontier-lang-kernel';
6
+ import type { FrontierCompileTarget } from './compile.js';
7
+ import type { NativeImportKnownLossKind } from './native-import-losses.js';
8
+ import type { NativeParserFeatureCategory } from './native-parser-features.js';
9
+ import type { ProjectionSourceProjectionCoverage, ProjectionTargetCoverageEntry } from './projection-coverage.js';
10
+ import type { ProjectionReadinessTargetCell } from './projection-readiness.js';
11
+ import type { UniversalCapabilityMatrix, UniversalCapabilityMatrixOptions } from './universal-capability.js';
12
+
13
+ export type UniversalConversionRouteMode =
14
+ | 'preserve-source'
15
+ | 'target-adapter'
16
+ | 'stub-only'
17
+ | 'semantic-index-only'
18
+ | 'blocked';
19
+
20
+ export type UniversalConversionRouteAction =
21
+ | 'preserve-source'
22
+ | 'run-target-adapter'
23
+ | 'attach-adapter-evidence'
24
+ | 'emit-stub'
25
+ | 'add-target-adapter'
26
+ | 'blocked';
27
+
28
+ export type UniversalConversionAdmissionAction = 'admit' | 'prioritize' | 'reject';
29
+ export type UniversalConversionPriority = 'low' | 'normal' | 'high' | 'blocker';
30
+ export type UniversalConversionRisk = 'low' | 'medium' | 'high';
31
+
32
+ export type UniversalConversionScoreComponentKey =
33
+ | 'importEvidence'
34
+ | 'parserEvidence'
35
+ | 'semanticIndex'
36
+ | 'projectionPath'
37
+ | 'proofEvidence';
38
+
39
+ export interface UniversalConversionScoreComponent {
40
+ readonly key: UniversalConversionScoreComponentKey;
41
+ readonly score: number;
42
+ readonly weight: number;
43
+ readonly weightedScore: number;
44
+ readonly status: 'strong' | 'partial' | 'weak' | 'blocked';
45
+ readonly reasons: readonly string[];
46
+ readonly signals: Record<string, unknown>;
47
+ }
48
+
49
+ export interface UniversalConversionMergeScore {
50
+ readonly schema: 'frontier.lang.semanticMergeScore.v1';
51
+ readonly version: 1;
52
+ readonly value: number;
53
+ readonly uncappedValue: number;
54
+ readonly sortKey: number;
55
+ readonly higherIsBetter: true;
56
+ readonly readiness: SemanticMergeReadiness;
57
+ readonly risk: UniversalConversionRisk;
58
+ readonly action: UniversalConversionAdmissionAction;
59
+ readonly components: Readonly<Record<UniversalConversionScoreComponentKey, UniversalConversionScoreComponent>>;
60
+ readonly penalties: readonly string[];
61
+ }
62
+
63
+ export interface UniversalConversionRouteEvidence {
64
+ readonly imports: number;
65
+ readonly importReadiness: SemanticMergeReadiness;
66
+ readonly symbols: number;
67
+ readonly sourceMaps: number;
68
+ readonly sourceMapMappings: number;
69
+ readonly losses: number;
70
+ readonly parserRows: number;
71
+ readonly mergeReadyParsers: number;
72
+ readonly exactSourceImports: number;
73
+ readonly declarationImports: number;
74
+ readonly targetSupported: boolean;
75
+ readonly targetAdapter?: string;
76
+ readonly targetLossKinds: readonly NativeImportKnownLossKind[];
77
+ }
78
+
79
+ export interface UniversalConversionRouteMergeRefs {
80
+ readonly planId: string;
81
+ readonly routeId: string;
82
+ readonly historyIds: readonly string[];
83
+ readonly patchBundleIds: readonly string[];
84
+ readonly patchIds: readonly string[];
85
+ readonly mergeCandidateIds: readonly string[];
86
+ readonly replayLinks: readonly unknown[];
87
+ readonly evidenceIds: readonly string[];
88
+ readonly proofIds: readonly string[];
89
+ readonly sources: readonly {
90
+ readonly sourceId?: string;
91
+ readonly importId?: string;
92
+ readonly sourcePath?: string;
93
+ readonly sourceHash?: string;
94
+ readonly baseHash?: string;
95
+ readonly targetHash?: string;
96
+ }[];
97
+ readonly semanticOwnershipKeys: readonly string[];
98
+ readonly conflictKeys: readonly string[];
99
+ readonly sourceMapIds: readonly string[];
100
+ readonly sourceMapMappingIds: readonly string[];
101
+ readonly sourceMapLinkIds: readonly string[];
102
+ readonly readiness: SemanticMergeReadiness;
103
+ readonly admissionStatus: UniversalConversionAdmissionAction;
104
+ readonly metadata: Record<string, unknown>;
105
+ }
106
+
107
+ export interface UniversalConversionRoute {
108
+ readonly id: string;
109
+ readonly sourceLanguage: FrontierSourceLanguage | string;
110
+ readonly languageIds: readonly string[];
111
+ readonly target: FrontierCompileTarget | string;
112
+ readonly mode: UniversalConversionRouteMode;
113
+ readonly routeAction: UniversalConversionRouteAction;
114
+ readonly admissionAction: UniversalConversionAdmissionAction;
115
+ readonly priority: UniversalConversionPriority;
116
+ readonly readiness: SemanticMergeReadiness;
117
+ readonly lossClass: string;
118
+ readonly adapter?: string;
119
+ readonly adapterKind?: string;
120
+ readonly sourceProjection?: {
121
+ readonly exactSource: ProjectionSourceProjectionCoverage;
122
+ readonly stubs: ProjectionSourceProjectionCoverage;
123
+ };
124
+ readonly projectionReadiness?: ProjectionReadinessTargetCell;
125
+ readonly evidence: UniversalConversionRouteEvidence;
126
+ readonly missingEvidence: readonly string[];
127
+ readonly blockers: readonly string[];
128
+ readonly review: readonly string[];
129
+ readonly tasks: readonly string[];
130
+ readonly mergeScore: UniversalConversionMergeScore;
131
+ readonly mergeRefs: UniversalConversionRouteMergeRefs;
132
+ readonly autoMergeClaim: false;
133
+ readonly semanticEquivalenceClaim: false;
134
+ readonly metadata: Record<string, unknown>;
135
+ }
136
+
137
+ export interface UniversalConversionPlan {
138
+ readonly kind: 'frontier.lang.universalConversionPlan';
139
+ readonly version: 1;
140
+ readonly id: string;
141
+ readonly generatedAt: number;
142
+ readonly routes: readonly UniversalConversionRoute[];
143
+ readonly summary: {
144
+ readonly routes: number;
145
+ readonly byMode: Readonly<Record<UniversalConversionRouteMode, number>>;
146
+ readonly byReadiness: Readonly<Record<SemanticMergeReadiness, number>>;
147
+ readonly byAdmissionAction: Readonly<Record<UniversalConversionAdmissionAction, number>>;
148
+ readonly readyRoutes: number;
149
+ readonly reviewRoutes: number;
150
+ readonly blockedRoutes: number;
151
+ readonly preserveSourceRoutes: number;
152
+ readonly targetAdapterRoutes: number;
153
+ readonly stubOnlyRoutes: number;
154
+ readonly semanticIndexOnlyRoutes: number;
155
+ readonly missingEvidence: number;
156
+ readonly blockers: number;
157
+ readonly reviewReasons: number;
158
+ readonly autoMergeClaims: 0;
159
+ readonly semanticEquivalenceClaims: 0;
160
+ };
161
+ readonly matrices: {
162
+ readonly universalCapability: UniversalCapabilityMatrix;
163
+ readonly projectionReadiness?: UniversalCapabilityMatrix['matrices']['projectionReadiness'];
164
+ readonly projectionTargets?: UniversalCapabilityMatrix['matrices']['projectionTargets'];
165
+ };
166
+ readonly metadata: {
167
+ readonly compileTargets: readonly (FrontierCompileTarget | string)[];
168
+ readonly requiredFeatures: readonly NativeParserFeatureCategory[];
169
+ readonly autoMergeClaim: false;
170
+ readonly semanticEquivalenceClaim: false;
171
+ readonly note: string;
172
+ };
173
+ }
174
+
175
+ export interface UniversalConversionPlanOptions extends UniversalCapabilityMatrixOptions {
176
+ readonly id?: string;
177
+ readonly universalCapabilityMatrix?: UniversalCapabilityMatrix;
178
+ readonly evidence?: readonly EvidenceRecord[];
179
+ }
180
+
181
+ export interface UniversalConversionPlanQuery {
182
+ readonly sourceLanguage?: FrontierSourceLanguage | string;
183
+ readonly language?: FrontierSourceLanguage | string;
184
+ readonly target?: FrontierCompileTarget | string;
185
+ readonly mode?: UniversalConversionRouteMode;
186
+ readonly readiness?: SemanticMergeReadiness;
187
+ readonly admissionAction?: UniversalConversionAdmissionAction;
188
+ }
189
+
190
+ export interface UniversalConversionPlanQueryResult {
191
+ readonly kind: 'frontier.lang.universalConversionPlanQuery';
192
+ readonly version: 1;
193
+ readonly found: boolean;
194
+ readonly routes: readonly UniversalConversionRoute[];
195
+ readonly bestRoute?: UniversalConversionRoute;
196
+ readonly reasons: readonly string[];
197
+ }
198
+
199
+ export declare function createUniversalConversionPlan(options?: UniversalConversionPlanOptions): UniversalConversionPlan;
200
+ export declare function queryUniversalConversionPlan(
201
+ planOrOptions?: UniversalConversionPlan | UniversalConversionPlanOptions,
202
+ query?: UniversalConversionPlanQuery
203
+ ): UniversalConversionPlanQueryResult;
package/dist/index.d.ts CHANGED
@@ -6,6 +6,7 @@ export * from './declarations/native-import-coverage.js';
6
6
  export * from './declarations/projection-coverage.js';
7
7
  export * from './declarations/projection-readiness.js';
8
8
  export * from './declarations/universal-capability.js';
9
+ export * from './declarations/universal-conversion-plan.js';
9
10
  export * from './declarations/universal-dialects.js';
10
11
  export * from './declarations/language-adapter-package-contracts.js';
11
12
  export * from './declarations/native-import-contracts.js';
@@ -17,6 +18,7 @@ export * from './declarations/semantic-patch-bundle.js';
17
18
  export * from './declarations/semantic-sidecar.js';
18
19
  export * from './declarations/native-diff.js';
19
20
  export * from './declarations/semantic-slice.js';
21
+ export * from './declarations/semantic-slice-admission.js';
20
22
  export * from './declarations/adapter-coverage.js';
21
23
  export * from './declarations/import-adapter-core.js';
22
24
  export * from './declarations/import-adapter-options-native.js';
package/dist/index.js CHANGED
@@ -23,11 +23,13 @@ export { createPythonAstNativeImporterAdapter } from './internal/index-impl/crea
23
23
  export { createRustSynNativeImporterAdapter } from './internal/index-impl/createRustSynNativeImporterAdapter.js';
24
24
  export { createSemanticImportSidecar } from './internal/index-impl/createSemanticImportSidecar.js';
25
25
  export { createSemanticSlice } from './internal/index-impl/createSemanticSlice.js';
26
+ export { createSemanticSliceAdmissionRecord } from './internal/index-impl/createSemanticSliceAdmissionRecord.js';
26
27
  export { createSwiftSyntaxNativeImporterAdapter } from './internal/index-impl/createSwiftSyntaxNativeImporterAdapter.js';
27
28
  export { createTreeSitterNativeImporterAdapter } from './internal/index-impl/createTreeSitterNativeImporterAdapter.js';
28
29
  export { createTypeScriptCompilerNativeImporterAdapter } from './internal/index-impl/createTypeScriptCompilerNativeImporterAdapter.js';
29
30
  export { createUniversalAstFromDocument } from './internal/index-impl/createUniversalAstFromDocument.js';
30
31
  export { createUniversalCapabilityMatrix } from './internal/index-impl/createUniversalCapabilityMatrix.js';
32
+ export { createUniversalConversionPlan } from './internal/index-impl/createUniversalConversionPlan.js';
31
33
  export { attachUniversalDialectRegistry, createUniversalDialectRecord, createUniversalDialectRegistry, createUniversalExternRecord, summarizeUniversalDialectRegistry, UniversalDialectConstructKinds, UniversalDialectProjectionDispositions } from './universal-dialect-registry.js';
32
34
  export { diffNativeSourceImports } from './internal/index-impl/diffNativeSourceImports.js';
33
35
  export { diffNativeSources } from './internal/index-impl/diffNativeSources.js';
@@ -61,6 +63,7 @@ export { queryNativeParserFeatureMatrix } from './internal/index-impl/queryNativ
61
63
  export { queryProjectionReadinessMatrix } from './internal/index-impl/queryProjectionReadinessMatrix.js';
62
64
  export { createSemanticPatchBundleRecord, querySemanticPatchBundleRecords, SemanticPatchBundleAdmissionStatuses } from './internal/index-impl/semanticPatchBundleRecords.js';
63
65
  export { querySemanticMergeConflictClasses, SemanticMergeConflictClasses, semanticMergeConflictRiskScore, sortSemanticMergeCandidatesByConflictRisk, summarizeSemanticMergeConflicts } from './internal/index-impl/semanticMergeConflicts.js';
66
+ export { queryUniversalConversionPlan } from './internal/index-impl/queryUniversalConversionPlan.js';
64
67
  export { createSemanticHistoryRecord, querySemanticHistoryRecordOverlaps, SemanticHistoryAdmissionStatuses, SemanticHistoryConflictReasons, SemanticHistoryOverlapKinds, SemanticHistoryReviewerStatuses, semanticHistoryRecordsConflict, semanticHistoryRecordsOverlap } from './internal/index-impl/semanticHistoryRecords.js';
65
68
  export { readSemanticSliceJson } from './internal/index-impl/readSemanticSliceJson.js';
66
69
  export { readUniversalAstJson } from './internal/index-impl/readUniversalAstJson.js';
@@ -0,0 +1,180 @@
1
+ import{idFragment,maxSemanticMergeReadiness,uniqueStrings}from'../../native-import-utils.js';
2
+ import{testSemanticSlice}from'./testSemanticSlice.js';
3
+
4
+ const readinessScore=Object.freeze({ready:100,'ready-with-losses':78,'needs-review':48,blocked:0});
5
+ const readinessRank=Object.freeze({ready:3,'ready-with-losses':2,'needs-review':1,blocked:0});
6
+ const actionRank=Object.freeze({admit:2,prioritize:1,reject:0});
7
+ const riskRank=Object.freeze({low:3,medium:2,unknown:1,high:0});
8
+
9
+ export function createSemanticSliceAdmissionRecord(slice,options={}){
10
+ const testResult=options.testResult??(options.currentSources?testSemanticSlice(slice,options):undefined);
11
+ const readiness=worstReadiness(slice?.mergeAdmission?.readiness??slice?.summary?.readiness??'needs-review',testResult?.readiness??'ready');
12
+ const components={
13
+ semanticSelection:semanticSelectionScore(slice),
14
+ sourceFreshness:sourceFreshnessScore(slice,testResult),
15
+ ownershipIsolation:ownershipIsolationScore(slice),
16
+ verificationEvidence:verificationEvidenceScore(slice,testResult,options),
17
+ reviewRisk:reviewRiskScore(slice,readiness,testResult)
18
+ };
19
+ const value=mergeScoreValue(components,readiness);
20
+ const action=admissionAction(slice,readiness,components,testResult);
21
+ const risk=admissionRisk(readiness,components,testResult);
22
+ return{
23
+ kind:'frontier.lang.semanticSliceAdmission',
24
+ version:1,
25
+ id:options.id??`semantic_slice_admission_${idFragment(slice?.id??'slice')}`,
26
+ generatedAt:options.generatedAt??Date.now(),
27
+ sliceId:slice?.id,
28
+ importId:slice?.importId,
29
+ sourcePath:slice?.sourcePath,
30
+ action,
31
+ priority:admissionPriority(action,risk,readiness),
32
+ readiness,
33
+ risk,
34
+ autoMergeClaim:false,
35
+ reviewRequired:action!=='admit'||readiness!=='ready',
36
+ mergeScore:{
37
+ schema:'frontier.lang.semanticMergeScore.v1',
38
+ version:1,
39
+ value,
40
+ uncappedValue:value,
41
+ sortKey:mergeScoreSortKey(value,action,risk,readiness),
42
+ higherIsBetter:true,
43
+ readiness,
44
+ risk,
45
+ action,
46
+ components,
47
+ penalties:uniqueStrings(Object.values(components).flatMap((component)=>component.score<100?component.reasons:[]))
48
+ },
49
+ counts:{
50
+ symbols:slice?.summary?.symbols??slice?.symbols?.length??0,
51
+ ownershipRegions:slice?.summary?.ownershipRegions??slice?.ownershipRegions?.length??0,
52
+ nativeNodes:slice?.summary?.nativeNodes??slice?.nativeNodes?.length??0,
53
+ sourceMapLinks:slice?.summary?.sourceMapLinks??slice?.sourceMapLinks?.length??0,
54
+ sourceFiles:slice?.summary?.sourceFiles??slice?.sourceFiles?.length??0,
55
+ focusedCommands:slice?.verification?.focusedCommands?.length??0,
56
+ fixtureHints:slice?.verification?.fixtureHints?.length??0,
57
+ assertions:testResult?.summary?.assertions??0,
58
+ failedAssertions:testResult?.summary?.failed??0,
59
+ warningAssertions:testResult?.summary?.warnings??0
60
+ },
61
+ conflictKeys:uniqueStrings(slice?.mergeAdmission?.conflictKeys??[]),
62
+ ownershipKeys:uniqueStrings(slice?.mergeAdmission?.ownershipKeys??[]),
63
+ sourceHashes:slice?.mergeAdmission?.sourceHashes??[],
64
+ testResult,
65
+ reasons:uniqueStrings([
66
+ ...(slice?.mergeAdmission?.reasons??[]),
67
+ ...Object.values(components).flatMap((component)=>component.reasons)
68
+ ]),
69
+ metadata:{
70
+ note:'Semantic slice admission is sortable merge-review evidence for isolated worker inputs; it is not a correctness proof and never grants auto-merge by itself.',
71
+ ...(options.metadata??{})
72
+ }
73
+ };
74
+ }
75
+
76
+ function semanticSelectionScore(slice){
77
+ const symbols=slice?.summary?.symbols??slice?.symbols?.length??0;
78
+ const regions=slice?.summary?.ownershipRegions??slice?.ownershipRegions?.length??0;
79
+ const nativeNodes=slice?.summary?.nativeNodes??slice?.nativeNodes?.length??0;
80
+ const links=slice?.summary?.sourceMapLinks??slice?.sourceMapLinks?.length??0;
81
+ const unresolved=slice?.summary?.unresolvedEntryRefs??slice?.unresolvedEntryRefs?.length??0;
82
+ const selected=symbols+regions+nativeNodes;
83
+ let score=selected>0?70:0;
84
+ if(symbols>0)score+=12;
85
+ if(regions>0)score+=10;
86
+ if(links>0)score+=8;
87
+ score=Math.max(0,Math.min(100,score-unresolved*25));
88
+ return scoreComponent('semanticSelection',score,[
89
+ ...(selected===0?['Slice selected no symbols, ownership regions, or native nodes.']:[]),
90
+ ...(unresolved?[`${unresolved} semantic slice entry ref(s) did not resolve.`]:[])
91
+ ],{symbols,ownershipRegions:regions,nativeNodes,sourceMapLinks:links,unresolvedEntryRefs:unresolved});
92
+ }
93
+
94
+ function sourceFreshnessScore(slice,testResult){
95
+ const sourceHashes=slice?.mergeAdmission?.sourceHashes??[];
96
+ const checks=(testResult?.assertions??[]).filter((assertion)=>String(assertion.id??'').startsWith('sourceHash:'));
97
+ const failed=checks.filter((assertion)=>assertion.status==='failed').length;
98
+ const warnings=checks.filter((assertion)=>assertion.status==='warning').length;
99
+ const passed=checks.filter((assertion)=>assertion.status==='passed').length;
100
+ const score=failed?0:checks.length?Math.max(20,Math.round((passed*100+warnings*55)/checks.length)):sourceHashes.length?55:35;
101
+ return scoreComponent('sourceFreshness',score,[
102
+ ...(failed?[`${failed} source hash check(s) failed.`]:[]),
103
+ ...(!checks.length&&sourceHashes.length?['Slice has source hashes but no current source check was run.']:[]),
104
+ ...(!sourceHashes.length?['Slice has no source hashes for stale-check admission.']:[])
105
+ ],{sourceHashes:sourceHashes.length,checks:checks.length,passed,warnings,failed});
106
+ }
107
+
108
+ function ownershipIsolationScore(slice){
109
+ const conflictKeys=slice?.mergeAdmission?.conflictKeys?.length??0;
110
+ const ownershipKeys=slice?.mergeAdmission?.ownershipKeys?.length??0;
111
+ const reviewRequired=slice?.mergeAdmission?.reviewRequired===true;
112
+ const score=conflictKeys?Math.max(45,100-Math.max(0,conflictKeys-1)*8-(reviewRequired?16:0)):15;
113
+ return scoreComponent('ownershipIsolation',score,[
114
+ ...(!conflictKeys?['Slice exposes no conflict keys for ownership isolation.']:[]),
115
+ ...(reviewRequired?['Slice merge admission already requires review.']:[])
116
+ ],{conflictKeys,ownershipKeys,reviewRequired});
117
+ }
118
+
119
+ function verificationEvidenceScore(slice,testResult,options){
120
+ const focused=slice?.verification?.focusedCommands?.length??0;
121
+ const fixtures=slice?.verification?.fixtureHints?.length??0;
122
+ const evidence=[...(options.evidence??[]),...(slice?.evidence??[])];
123
+ const failed=(testResult?.summary?.failed??0)+evidence.filter((record)=>record?.status==='failed').length;
124
+ const warnings=testResult?.summary?.warnings??0;
125
+ let score=focused||fixtures||evidence.length?72:45;
126
+ score+=Math.min(18,focused*8+fixtures*4+evidence.length*3);
127
+ score-=failed*35+warnings*8;
128
+ return scoreComponent('verificationEvidence',Math.max(0,Math.min(100,score)),[
129
+ ...(!focused?['Slice has no focused verification command.']:[]),
130
+ ...(failed?[`${failed} failed assertion or evidence record(s).`]:[])
131
+ ],{focusedCommands:focused,fixtureHints:fixtures,evidenceRecords:evidence.length,failed,warnings});
132
+ }
133
+
134
+ function reviewRiskScore(slice,readiness,testResult){
135
+ const losses=slice?.summary?.losses??slice?.losses?.length??0;
136
+ const failed=testResult?.summary?.failed??0;
137
+ const base=readinessScore[readiness]??48;
138
+ const score=Math.max(0,Math.min(100,base-losses*4-failed*25));
139
+ return scoreComponent('reviewRisk',score,[
140
+ ...(readiness!=='ready'?[`Slice readiness is ${readiness}.`]:[]),
141
+ ...(losses?[`Slice carries ${losses} native import loss record(s).`]:[])
142
+ ],{readiness,losses,failedAssertions:failed});
143
+ }
144
+
145
+ function scoreComponent(key,score,reasons,signals){
146
+ const rounded=Math.round(Math.max(0,Math.min(100,score)));
147
+ return{key,score:rounded,weight:20,weightedScore:rounded*20/100,status:rounded>=85?'strong':rounded>=60?'partial':rounded>0?'weak':'blocked',reasons,signals};
148
+ }
149
+
150
+ function mergeScoreValue(components,readiness){
151
+ const values=Object.values(components);
152
+ const score=values.reduce((sum,component)=>sum+component.weightedScore,0)/values.reduce((sum,component)=>sum+component.weight,0)*100;
153
+ return Math.round(Math.max(0,Math.min(readiness==='blocked'?35:100,score)));
154
+ }
155
+
156
+ function admissionAction(slice,readiness,components,testResult){
157
+ if(readiness==='blocked'||(testResult?.summary?.failed??0)>0||components.semanticSelection.score===0||components.sourceFreshness.score===0)return'reject';
158
+ if(readiness!=='ready'||slice?.mergeAdmission?.reviewRequired||Object.values(components).some((component)=>component.score<70))return'prioritize';
159
+ return'admit';
160
+ }
161
+
162
+ function admissionRisk(readiness,components,testResult){
163
+ if(readiness==='blocked'||(testResult?.summary?.failed??0)>0)return'high';
164
+ if(readiness==='needs-review'||Object.values(components).some((component)=>component.score<60))return'medium';
165
+ return'low';
166
+ }
167
+
168
+ function admissionPriority(action,risk,readiness){
169
+ if(action==='reject')return'blocker';
170
+ if(readiness==='needs-review'||risk==='medium')return'high';
171
+ return action==='prioritize'?'normal':'low';
172
+ }
173
+
174
+ function mergeScoreSortKey(value,action,risk,readiness){
175
+ return value+(actionRank[action]??0)*1000+(riskRank[risk]??0)*100+(readinessRank[readiness]??0)*10;
176
+ }
177
+
178
+ function worstReadiness(...values){
179
+ return values.reduce((current,value)=>maxSemanticMergeReadiness(current,value??'ready'),'ready');
180
+ }
@@ -0,0 +1,5 @@
1
+ import{createUniversalConversionPlan as createUniversalConversionPlanImpl}from'../../universal-conversion-plan.js';
2
+ import{coverageMatrixContext}from'./coverageMatrixContext.js';
3
+ export function createUniversalConversionPlan(input = {}) {
4
+ return createUniversalConversionPlanImpl(input, coverageMatrixContext());
5
+ }
@@ -0,0 +1,5 @@
1
+ import{queryUniversalConversionPlan as queryUniversalConversionPlanImpl}from'../../universal-conversion-plan.js';
2
+ import{coverageMatrixContext}from'./coverageMatrixContext.js';
3
+ export function queryUniversalConversionPlan(planOrInput = {}, query = {}) {
4
+ return queryUniversalConversionPlanImpl(planOrInput, query, coverageMatrixContext());
5
+ }
@@ -0,0 +1,125 @@
1
+ import {
2
+ idFragment,
3
+ normalizeNativeLanguageId,
4
+ uniqueStrings
5
+ } from './native-import-utils.js';
6
+
7
+ export function importsForConversionLanguage(imports, language) {
8
+ const ids = new Set([language?.language, ...(language?.aliases ?? [])].map(normalizeNativeLanguageId).filter(Boolean));
9
+ return (imports ?? []).filter((imported) => ids.has(normalizeNativeLanguageId(imported?.language ?? imported?.nativeAst?.language)));
10
+ }
11
+
12
+ export function conversionMergeRefs(input) {
13
+ const routeImports = input.imports ?? [];
14
+ const routeId = input.routeId;
15
+ const sourceMaps = routeImports.flatMap(sourceMapsForImport);
16
+ return {
17
+ planId: input.planId,
18
+ routeId,
19
+ historyIds: [`history_${routeId}`],
20
+ patchBundleIds: [],
21
+ patchIds: [],
22
+ mergeCandidateIds: uniqueStrings(routeImports.flatMap(mergeCandidateIds)),
23
+ replayLinks: routeImports.flatMap((imported) => imported?.replayLinks ?? imported?.universalAst?.replayLinks ?? []),
24
+ evidenceIds: uniqueStrings(routeImports.flatMap((imported) => evidenceRecords(imported).map((record) => record.id))),
25
+ proofIds: uniqueStrings(routeImports.flatMap(proofIdsForImport)),
26
+ sources: routeImports.map(conversionSourceRef),
27
+ semanticOwnershipKeys: uniqueStrings(routeImports.flatMap(semanticOwnershipKeysForImport)),
28
+ conflictKeys: uniqueStrings(routeImports.flatMap(conflictKeysForImport)),
29
+ sourceMapIds: uniqueStrings(sourceMaps.map((sourceMap) => sourceMap?.id)),
30
+ sourceMapMappingIds: uniqueStrings(sourceMaps.flatMap((sourceMap) => (sourceMap?.mappings ?? []).map((mapping) => mapping.id))),
31
+ sourceMapLinkIds: [],
32
+ readiness: input.readiness,
33
+ admissionStatus: input.admissionStatus,
34
+ metadata: {
35
+ plannedHistoryId: true,
36
+ note: 'Merge refs are compact route provenance for semantic history and patch-bundle builders; planned IDs are not proof records until materialized.'
37
+ }
38
+ };
39
+ }
40
+
41
+ function conversionSourceRef(imported) {
42
+ return {
43
+ sourceId: imported?.nativeSource?.id ?? imported?.id,
44
+ importId: imported?.id,
45
+ sourcePath: imported?.sourcePath ?? imported?.nativeSource?.sourcePath,
46
+ sourceHash: imported?.sourceHash
47
+ ?? imported?.nativeSource?.sourceHash
48
+ ?? imported?.metadata?.sourcePreservation?.sourceHash,
49
+ baseHash: imported?.baseHash ?? imported?.metadata?.baseHash,
50
+ targetHash: imported?.targetHash ?? imported?.metadata?.targetHash
51
+ };
52
+ }
53
+
54
+ function evidenceRecords(imported) {
55
+ return [
56
+ ...(imported?.evidence ?? []),
57
+ ...(imported?.universalAst?.evidence ?? []),
58
+ ...(imported?.patch?.evidence ?? [])
59
+ ].filter((record) => record?.id);
60
+ }
61
+
62
+ function proofIdsForImport(imported) {
63
+ return [
64
+ ...(imported?.proofIds ?? []),
65
+ ...evidenceRecords(imported).filter((record) => record?.kind === 'proof' || record?.type === 'proof').map((record) => record.id)
66
+ ];
67
+ }
68
+
69
+ function mergeCandidateIds(imported) {
70
+ return (imported?.mergeCandidates ?? []).map((candidate) => candidate.id);
71
+ }
72
+
73
+ function sourceMapsForImport(imported) {
74
+ return [
75
+ ...(imported?.sourceMaps ?? []),
76
+ ...(imported?.universalAst?.sourceMaps ?? [])
77
+ ];
78
+ }
79
+
80
+ function semanticOwnershipKeysForImport(imported) {
81
+ return uniqueStrings([
82
+ ...ownershipKeysFromCandidates(imported),
83
+ ...ownershipKeysFromSourceMaps(imported),
84
+ ...ownershipKeysFromSymbols(imported)
85
+ ]);
86
+ }
87
+
88
+ function conflictKeysForImport(imported) {
89
+ return uniqueStrings([
90
+ ...conflictKeysFromCandidates(imported),
91
+ ...ownershipKeysFromSourceMaps(imported)
92
+ ]);
93
+ }
94
+
95
+ function ownershipKeysFromCandidates(imported) {
96
+ return uniqueStrings((imported?.mergeCandidates ?? []).flatMap((candidate) => [
97
+ ...(candidate?.ownershipKeys ?? []),
98
+ ...(candidate?.semanticOwnershipKeys ?? []),
99
+ ...(candidate?.changedRegions ?? []).map((region) => region?.key)
100
+ ]));
101
+ }
102
+
103
+ function conflictKeysFromCandidates(imported) {
104
+ return uniqueStrings((imported?.mergeCandidates ?? []).flatMap((candidate) => [
105
+ ...(candidate?.conflictKeys ?? []),
106
+ ...(candidate?.changedRegions ?? []).flatMap((region) => [region?.conflictKey, ...(region?.admission?.conflictKeys ?? [])])
107
+ ]));
108
+ }
109
+
110
+ function ownershipKeysFromSourceMaps(imported) {
111
+ return uniqueStrings(sourceMapsForImport(imported).flatMap((sourceMap) => (sourceMap?.mappings ?? []).flatMap((mapping) => [
112
+ mapping?.ownershipRegionKey,
113
+ mapping?.ownershipRegionId,
114
+ mapping?.ownershipRegionKind ? `${mapping.sourceSpan?.path ?? imported?.sourcePath ?? 'source'}#${mapping.ownershipRegionKind}` : undefined
115
+ ])));
116
+ }
117
+
118
+ function ownershipKeysFromSymbols(imported) {
119
+ const symbols = imported?.semanticIndex?.symbols ?? imported?.universalAst?.semanticIndex?.symbols ?? [];
120
+ return uniqueStrings(symbols.flatMap((symbol) => [
121
+ symbol?.metadata?.ownershipRegionKey,
122
+ symbol?.metadata?.ownershipRegionId,
123
+ symbol?.metadata?.ownershipRegionKind ? `${symbol.language ?? imported?.language ?? 'source'}#${idFragment(symbol.name)}#${symbol.metadata.ownershipRegionKind}` : undefined
124
+ ]));
125
+ }
@@ -0,0 +1,134 @@
1
+ import { uniqueStrings } from './native-import-utils.js';
2
+
3
+ const readinessScore = Object.freeze({ ready: 100, 'ready-with-losses': 76, 'needs-review': 48, blocked: 0 });
4
+ const readinessRank = Object.freeze({ ready: 3, 'ready-with-losses': 2, 'needs-review': 1, blocked: 0 });
5
+ const actionRank = Object.freeze({ admit: 2, prioritize: 1, reject: 0 });
6
+ const modeRank = Object.freeze({
7
+ 'preserve-source': 5,
8
+ 'target-adapter': 4,
9
+ 'stub-only': 3,
10
+ 'semantic-index-only': 2,
11
+ blocked: 0
12
+ });
13
+ const componentWeights = Object.freeze({
14
+ importEvidence: 22,
15
+ parserEvidence: 18,
16
+ semanticIndex: 18,
17
+ projectionPath: 24,
18
+ proofEvidence: 18
19
+ });
20
+
21
+ export function conversionScoreComponents(language, targetCell, readiness, mode, evidence) {
22
+ return {
23
+ importEvidence: scoreComponent('importEvidence', readinessScore[language.imports.readiness] ?? 48, [
24
+ ...(language.imports.total ? [] : ['No source import evidence.']),
25
+ ...(language.imports.readiness === 'ready' ? [] : [`Import readiness is ${language.imports.readiness}.`])
26
+ ], { imports: language.imports.total, losses: language.imports.losses }),
27
+ parserEvidence: scoreComponent('parserEvidence', parserScore(language), [
28
+ ...(language.parser.rows ? [] : ['No parser feature row matched this language.']),
29
+ ...(language.parser.blockingFeatures ?? []).map((feature) => `Parser feature is blocked: ${feature}.`)
30
+ ], { rows: language.parser.rows, mergeReadyParsers: language.parser.mergeReadyParsers.length }),
31
+ semanticIndex: scoreComponent('semanticIndex', semanticIndexScore(language), [
32
+ ...(language.imports.symbols ? [] : ['No semantic symbols were imported.']),
33
+ ...(language.imports.sourceMapMappings ? [] : ['No source-map mappings were imported.'])
34
+ ], { symbols: language.imports.symbols, sourceMapMappings: language.imports.sourceMapMappings }),
35
+ projectionPath: scoreComponent('projectionPath', projectionPathScore(targetCell, mode, readiness), projectionPathReasons(targetCell, mode), {
36
+ mode,
37
+ lossClass: targetCell?.lossClass,
38
+ adapter: targetCell?.adapter,
39
+ readiness
40
+ }),
41
+ proofEvidence: scoreComponent('proofEvidence', proofEvidenceScore(evidence), proofEvidenceReasons(evidence), {
42
+ records: evidence.length,
43
+ passed: evidence.filter((record) => passedEvidence(record)).length,
44
+ failed: evidence.filter((record) => record?.status === 'failed').length
45
+ })
46
+ };
47
+ }
48
+
49
+ export function conversionMergeScore(input) {
50
+ const weighted = Object.values(input.components).reduce((sum, component) => sum + component.weightedScore, 0);
51
+ const weight = Object.values(input.components).reduce((sum, component) => sum + component.weight, 0);
52
+ const uncappedValue = Math.round(weight ? weighted * 100 / weight : 0);
53
+ const action = input.blockers.length || input.readiness === 'blocked' || input.mode === 'blocked' ? 'reject'
54
+ : input.readiness === 'ready' && input.mode !== 'stub-only' && input.mode !== 'semantic-index-only' ? 'admit'
55
+ : 'prioritize';
56
+ const value = action === 'reject' ? Math.min(35, uncappedValue) : uncappedValue;
57
+ return {
58
+ schema: 'frontier.lang.semanticMergeScore.v1',
59
+ version: 1,
60
+ value,
61
+ uncappedValue,
62
+ sortKey: value + (actionRank[action] ?? 0) * 1000 + (modeRank[input.mode] ?? 0) * 100 + (readinessRank[input.readiness] ?? 0) * 10,
63
+ higherIsBetter: true,
64
+ readiness: input.readiness,
65
+ risk: input.readiness === 'blocked' ? 'high' : input.readiness === 'needs-review' ? 'medium' : 'low',
66
+ action,
67
+ components: input.components,
68
+ penalties: uniqueStrings([
69
+ ...(action === 'reject' ? ['Conversion route is rejected until blockers are resolved.'] : []),
70
+ ...Object.values(input.components).flatMap((component) => component.score < 100 ? component.reasons : [])
71
+ ])
72
+ };
73
+ }
74
+
75
+ function parserScore(language) {
76
+ if (!language.parser.rows) return 0;
77
+ return Math.min(100, (readinessScore[language.parser.readiness] ?? 48) + Math.min(16, language.parser.mergeReadyParsers.length * 8));
78
+ }
79
+
80
+ function semanticIndexScore(language) {
81
+ const symbols = language.imports.symbols ?? 0;
82
+ const mappings = language.imports.sourceMapMappings ?? 0;
83
+ if (!symbols) return 0;
84
+ return Math.min(100, 62 + Math.min(22, symbols * 3) + Math.min(16, mappings * 2));
85
+ }
86
+
87
+ function projectionPathScore(targetCell, mode, readiness) {
88
+ if (mode === 'blocked') return 0;
89
+ if (mode === 'preserve-source') return 92;
90
+ if (mode === 'target-adapter') return Math.min(92, (readinessScore[readiness] ?? 48) + (targetCell?.adapter ? 12 : 0));
91
+ if (mode === 'stub-only') return 44;
92
+ if (mode === 'semantic-index-only') return 30;
93
+ return 10;
94
+ }
95
+
96
+ function proofEvidenceScore(evidence) {
97
+ if (!evidence.length) return 45;
98
+ const passed = evidence.filter((record) => passedEvidence(record)).length;
99
+ const failed = evidence.filter((record) => record?.status === 'failed').length;
100
+ return Math.max(0, Math.min(100, 55 + passed * 12 - failed * 35));
101
+ }
102
+
103
+ function projectionPathReasons(targetCell, mode) {
104
+ return uniqueStrings([
105
+ ...(targetCell?.reason ? [targetCell.reason] : []),
106
+ ...(mode === 'blocked' ? ['Projection path is blocked.'] : []),
107
+ ...(mode === 'semantic-index-only' ? ['Semantic index can guide review, but code emission needs a target adapter.'] : [])
108
+ ]);
109
+ }
110
+
111
+ function proofEvidenceReasons(evidence) {
112
+ return uniqueStrings([
113
+ ...(!evidence.length ? ['No proof, oracle, test, or replay evidence was attached to this conversion route.'] : []),
114
+ ...(evidence.filter((record) => record?.status === 'failed').length ? ['At least one attached evidence record failed.'] : [])
115
+ ]);
116
+ }
117
+
118
+ function scoreComponent(key, score, reasons, signals) {
119
+ const normalized = Math.max(0, Math.min(100, Math.round(score)));
120
+ const weight = componentWeights[key];
121
+ return {
122
+ key,
123
+ score: normalized,
124
+ weight,
125
+ weightedScore: normalized * weight / 100,
126
+ status: normalized >= 80 ? 'strong' : normalized >= 50 ? 'partial' : normalized > 0 ? 'weak' : 'blocked',
127
+ reasons: uniqueStrings(reasons),
128
+ signals
129
+ };
130
+ }
131
+
132
+ function passedEvidence(record) {
133
+ return record?.status === 'passed' || record?.status === 'ok' || record?.status === 'success';
134
+ }
@@ -0,0 +1,279 @@
1
+ import {
2
+ idFragment,
3
+ maxSemanticMergeReadiness,
4
+ normalizeNativeLanguageId,
5
+ uniqueStrings
6
+ } from './native-import-utils.js';
7
+ import {
8
+ nativeLanguageCompileTarget,
9
+ normalizeProjectionMatrixTargets
10
+ } from './coverage-matrix-profiles.js';
11
+ import { createUniversalCapabilityMatrix } from './universal-capability-matrix.js';
12
+ import {
13
+ conversionMergeRefs,
14
+ importsForConversionLanguage
15
+ } from './universal-conversion-plan-merge-refs.js';
16
+ import {
17
+ conversionMergeScore,
18
+ conversionScoreComponents
19
+ } from './universal-conversion-plan-scoring.js';
20
+
21
+ export function createUniversalConversionPlan(input = {}, context = {}) {
22
+ const generatedAt = input.generatedAt ?? Date.now();
23
+ const id = input.id ?? conversionPlanId(input, generatedAt);
24
+ const matrix = input.universalCapabilityMatrix?.kind === 'frontier.lang.universalCapabilityMatrix'
25
+ ? input.universalCapabilityMatrix
26
+ : createUniversalCapabilityMatrix({ ...input, generatedAt }, context);
27
+ const targets = conversionTargets(input, matrix, context);
28
+ const evidence = input.evidence ?? [];
29
+ const routes = (matrix.languages ?? []).flatMap((language) => targets.map((target) => conversionRoute(language, target, {
30
+ evidence,
31
+ generatedAt,
32
+ imports: input.imports ?? [],
33
+ matrix
34
+ }, id)));
35
+ return {
36
+ kind: 'frontier.lang.universalConversionPlan',
37
+ version: 1,
38
+ id,
39
+ generatedAt,
40
+ routes,
41
+ summary: conversionPlanSummary(routes),
42
+ matrices: {
43
+ universalCapability: matrix,
44
+ projectionReadiness: matrix.matrices?.projectionReadiness,
45
+ projectionTargets: matrix.matrices?.projectionTargets
46
+ },
47
+ metadata: {
48
+ compileTargets: targets,
49
+ requiredFeatures: matrix.metadata?.requiredFeatures ?? [],
50
+ autoMergeClaim: false,
51
+ semanticEquivalenceClaim: false,
52
+ note: 'Conversion plans rank source-to-target routes and missing evidence for agent coordination. They do not prove semantic equivalence or grant auto-merge.'
53
+ }
54
+ };
55
+ }
56
+
57
+ export function queryUniversalConversionPlan(planOrInput = {}, query = {}, context = {}) {
58
+ const plan = planOrInput?.kind === 'frontier.lang.universalConversionPlan'
59
+ ? planOrInput
60
+ : createUniversalConversionPlan(planOrInput, context);
61
+ const sourceLanguage = normalizeNativeLanguageId(query.sourceLanguage ?? query.language);
62
+ const target = normalizeProjectionMatrixTargets(query.target ? [query.target] : [])[0];
63
+ const routes = (plan.routes ?? []).filter((route) => {
64
+ if (sourceLanguage && !route.languageIds.includes(sourceLanguage)) return false;
65
+ if (target && route.target !== target) return false;
66
+ if (query.mode && route.mode !== query.mode) return false;
67
+ if (query.readiness && route.readiness !== query.readiness) return false;
68
+ if (query.admissionAction && route.admissionAction !== query.admissionAction) return false;
69
+ return true;
70
+ });
71
+ return {
72
+ kind: 'frontier.lang.universalConversionPlanQuery',
73
+ version: 1,
74
+ found: routes.length > 0,
75
+ routes,
76
+ bestRoute: routes.slice().sort((a, b) => b.mergeScore.sortKey - a.mergeScore.sortKey)[0],
77
+ reasons: routes.length ? [] : [`No conversion route matched source=${query.sourceLanguage ?? query.language ?? '*'} target=${query.target ?? '*'}.`]
78
+ };
79
+ }
80
+
81
+ function conversionTargets(input, matrix, context) {
82
+ const explicit = normalizeProjectionMatrixTargets(input.targets ?? []);
83
+ if (explicit.length) return explicit;
84
+ const matrixTargets = normalizeProjectionMatrixTargets(matrix.metadata?.compileTargets ?? []);
85
+ if (matrixTargets.length) return matrixTargets;
86
+ return normalizeProjectionMatrixTargets(context.compileTargets ?? []);
87
+ }
88
+
89
+ function conversionRoute(language, target, input, planId) {
90
+ const sourceTarget = nativeLanguageCompileTarget(language.language, language.aliases) ?? normalizeNativeLanguageId(language.language);
91
+ const targetCell = (language.projection?.targets ?? []).find((entry) => entry.target === target);
92
+ const readinessCell = projectionReadinessCell(input.matrix, language, target);
93
+ const mode = conversionMode(language, target, sourceTarget, targetCell);
94
+ const blockers = conversionBlockers(language, targetCell, mode);
95
+ const review = conversionReviewReasons(language, targetCell, mode);
96
+ const readiness = blockers.length
97
+ ? 'blocked'
98
+ : maxSemanticMergeReadiness(language.readiness, targetCell?.readiness ?? readinessCell?.readiness ?? 'needs-review');
99
+ const components = conversionScoreComponents(language, targetCell, readiness, mode, input.evidence);
100
+ const mergeScore = conversionMergeScore({ readiness, mode, components, blockers, review });
101
+ const id = `conversion_${idFragment(language.language)}_to_${idFragment(target)}`;
102
+ const routeImports = importsForConversionLanguage(input.imports, language);
103
+ return {
104
+ id,
105
+ sourceLanguage: language.language,
106
+ languageIds: uniqueStrings([language.language, ...(language.aliases ?? [])].map(normalizeNativeLanguageId)),
107
+ target,
108
+ mode,
109
+ routeAction: conversionRouteAction(mode, targetCell, readiness),
110
+ admissionAction: mergeScore.action,
111
+ priority: conversionPriority(mergeScore.action, readiness, mode),
112
+ readiness,
113
+ lossClass: mode === 'preserve-source' ? 'exactSourceProjection' : targetCell?.lossClass ?? 'missingAdapter',
114
+ adapter: targetCell?.adapter,
115
+ adapterKind: targetCell?.adapterKind,
116
+ sourceProjection: language.projection?.sourceProjection,
117
+ projectionReadiness: readinessCell,
118
+ evidence: conversionEvidence(language, targetCell),
119
+ missingEvidence: conversionMissingEvidence(language, targetCell, mode),
120
+ blockers,
121
+ review,
122
+ tasks: conversionTasks(language, target, mode, blockers, review),
123
+ mergeScore,
124
+ mergeRefs: conversionMergeRefs({
125
+ planId,
126
+ routeId: id,
127
+ imports: routeImports,
128
+ readiness,
129
+ admissionStatus: mergeScore.action
130
+ }),
131
+ autoMergeClaim: false,
132
+ semanticEquivalenceClaim: false,
133
+ metadata: {
134
+ generatedAt: input.generatedAt,
135
+ note: 'Route readiness is merge-review evidence for a conversion attempt, not proof that emitted target code is semantically equivalent.'
136
+ }
137
+ };
138
+ }
139
+
140
+ function conversionPlanId(input, generatedAt) {
141
+ const languages = uniqueStrings((input.imports ?? []).map((imported) => imported?.language ?? imported?.nativeAst?.language));
142
+ const targets = normalizeProjectionMatrixTargets(input.targets ?? []);
143
+ return `universal_conversion_plan_${idFragment([...languages, 'to', ...targets, String(generatedAt)].join('_'))}`;
144
+ }
145
+
146
+ function conversionMode(language, target, sourceTarget, targetCell) {
147
+ const exactSourceImports = language.projection?.sourceProjection?.exactSource?.evidence?.importsWithExactSource ?? 0;
148
+ if (target === sourceTarget && exactSourceImports > 0) return 'preserve-source';
149
+ if (targetCell?.lossClass === 'targetAdapterProjection') return 'target-adapter';
150
+ if (targetCell?.lossClass === 'nativeSourceStubs') return 'stub-only';
151
+ if (targetCell?.lossClass === 'unsupportedTargetFeatures') return 'target-adapter';
152
+ if ((language.imports?.symbols ?? 0) > 0 && targetCell?.lossClass === 'missingAdapter') return 'semantic-index-only';
153
+ return 'blocked';
154
+ }
155
+
156
+ function conversionBlockers(language, targetCell, mode) {
157
+ return uniqueStrings([
158
+ ...(language.imports.total === 0 ? ['No source import exists for this language.'] : []),
159
+ ...(mode === 'blocked' ? ['No viable preserve, adapter, stub, or semantic-index conversion route exists.'] : []),
160
+ ...(targetCell?.lossClass === 'missingAdapter' && mode !== 'semantic-index-only' ? [targetCell.reason] : []),
161
+ ...(language.blockers ?? []).filter((reason) => !reason.includes('Missing native-to-target projection adapter'))
162
+ ]);
163
+ }
164
+
165
+ function conversionReviewReasons(language, targetCell, mode) {
166
+ return uniqueStrings([
167
+ ...(language.review ?? []),
168
+ ...(targetCell?.reason ? [targetCell.reason] : []),
169
+ ...(mode === 'stub-only' ? ['Route can emit declaration stubs only; executable semantics require a target adapter.'] : []),
170
+ ...(mode === 'semantic-index-only' ? ['Route has semantic index evidence but no target code projection adapter.'] : []),
171
+ ...(mode === 'target-adapter' ? ['Host target adapter evidence must be reviewed before accepting emitted target code.'] : [])
172
+ ]);
173
+ }
174
+
175
+ function projectionReadinessCell(matrix, language, target) {
176
+ const ids = uniqueStrings([language.language, ...(language.aliases ?? [])].map(normalizeNativeLanguageId));
177
+ return (matrix.matrices?.projectionReadiness?.languages ?? [])
178
+ .find((row) => ids.includes(normalizeNativeLanguageId(row.language)))
179
+ ?.targets?.find((entry) => entry.target === target);
180
+ }
181
+
182
+ function conversionRouteAction(mode, targetCell, readiness) {
183
+ if (mode === 'blocked') return 'blocked';
184
+ if (mode === 'preserve-source') return 'preserve-source';
185
+ if (mode === 'stub-only') return 'emit-stub';
186
+ if (mode === 'semantic-index-only') return 'add-target-adapter';
187
+ if (targetCell?.lossClass === 'unsupportedTargetFeatures') return 'attach-adapter-evidence';
188
+ return 'run-target-adapter';
189
+ }
190
+
191
+ function conversionPriority(action, readiness, mode) {
192
+ if (action === 'reject' || readiness === 'blocked') return 'blocker';
193
+ if (mode === 'semantic-index-only' || readiness === 'needs-review') return 'high';
194
+ if (mode === 'stub-only' || readiness === 'ready-with-losses') return 'normal';
195
+ return 'low';
196
+ }
197
+
198
+ function conversionEvidence(language, targetCell) {
199
+ return {
200
+ imports: language.imports.total,
201
+ importReadiness: language.imports.readiness,
202
+ symbols: language.imports.symbols,
203
+ sourceMaps: language.imports.sourceMaps,
204
+ sourceMapMappings: language.imports.sourceMapMappings,
205
+ losses: language.imports.losses,
206
+ parserRows: language.parser.rows,
207
+ mergeReadyParsers: language.parser.mergeReadyParsers.length,
208
+ exactSourceImports: language.projection?.sourceProjection?.exactSource?.evidence?.importsWithExactSource ?? 0,
209
+ declarationImports: language.projection?.sourceProjection?.stubs?.evidence?.importsWithDeclarations ?? 0,
210
+ targetSupported: targetCell?.supported === true,
211
+ targetAdapter: targetCell?.adapter,
212
+ targetLossKinds: targetCell?.lossKinds ?? []
213
+ };
214
+ }
215
+
216
+ function conversionMissingEvidence(language, targetCell, mode) {
217
+ return uniqueStrings([
218
+ ...(language.imports.total ? [] : ['source-import']),
219
+ ...(language.imports.symbols ? [] : ['semantic-index']),
220
+ ...(language.imports.sourceMapMappings ? [] : ['source-map']),
221
+ ...(language.parser.mergeReadyParsers.length ? [] : ['merge-ready-parser']),
222
+ ...((language.projection?.sourceProjection?.exactSource?.evidence?.importsWithExactSource ?? 0) ? [] : ['source-preservation-hash']),
223
+ ...(mode === 'target-adapter' && !targetCell?.adapter ? ['target-adapter-evidence'] : []),
224
+ ...(mode === 'semantic-index-only' || targetCell?.lossClass === 'missingAdapter' ? ['target-adapter'] : []),
225
+ ...(mode === 'stub-only' ? ['executable-target-semantics'] : []),
226
+ ['proof-or-replay-evidence']
227
+ ]);
228
+ }
229
+
230
+ function conversionTasks(language, target, mode, blockers, review) {
231
+ return uniqueStrings([
232
+ ...(language.imports.total ? [] : [`import ${language.language} source before planning ${target} output`]),
233
+ ...(language.imports.symbols ? [] : [`attach semantic index for ${language.language}`]),
234
+ ...(language.parser.mergeReadyParsers.length ? [] : [`provide merge-ready parser evidence for ${language.language}`]),
235
+ ...(mode === 'semantic-index-only' || mode === 'blocked' ? [`add ${language.language} to ${target} target adapter`] : []),
236
+ ...(mode === 'stub-only' ? [`replace ${target} declaration stubs with executable adapter output`] : []),
237
+ ...(mode === 'target-adapter' ? [`run and verify ${language.language} to ${target} target adapter`] : []),
238
+ ...(blockers.length || review.length ? [`collect proof, replay, or oracle evidence for ${language.language} to ${target}`] : [])
239
+ ]);
240
+ }
241
+
242
+ function conversionPlanSummary(routes) {
243
+ const summary = {
244
+ routes: routes.length,
245
+ byMode: {},
246
+ byReadiness: {},
247
+ byAdmissionAction: {},
248
+ readyRoutes: 0,
249
+ reviewRoutes: 0,
250
+ blockedRoutes: 0,
251
+ preserveSourceRoutes: 0,
252
+ targetAdapterRoutes: 0,
253
+ stubOnlyRoutes: 0,
254
+ semanticIndexOnlyRoutes: 0,
255
+ missingEvidence: 0,
256
+ blockers: 0,
257
+ reviewReasons: 0,
258
+ autoMergeClaims: 0,
259
+ semanticEquivalenceClaims: 0
260
+ };
261
+ for (const route of routes) {
262
+ summary.byMode[route.mode] = (summary.byMode[route.mode] ?? 0) + 1;
263
+ summary.byReadiness[route.readiness] = (summary.byReadiness[route.readiness] ?? 0) + 1;
264
+ summary.byAdmissionAction[route.admissionAction] = (summary.byAdmissionAction[route.admissionAction] ?? 0) + 1;
265
+ if (route.readiness === 'ready') summary.readyRoutes += 1;
266
+ if (route.readiness === 'needs-review' || route.readiness === 'ready-with-losses') summary.reviewRoutes += 1;
267
+ if (route.readiness === 'blocked') summary.blockedRoutes += 1;
268
+ if (route.mode === 'preserve-source') summary.preserveSourceRoutes += 1;
269
+ if (route.mode === 'target-adapter') summary.targetAdapterRoutes += 1;
270
+ if (route.mode === 'stub-only') summary.stubOnlyRoutes += 1;
271
+ if (route.mode === 'semantic-index-only') summary.semanticIndexOnlyRoutes += 1;
272
+ summary.missingEvidence += route.missingEvidence.length;
273
+ summary.blockers += route.blockers.length;
274
+ summary.reviewReasons += route.review.length;
275
+ if (route.autoMergeClaim) summary.autoMergeClaims += 1;
276
+ if (route.semanticEquivalenceClaim) summary.semanticEquivalenceClaims += 1;
277
+ }
278
+ return summary;
279
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shapeshift-labs/frontier-lang-compiler",
3
- "version": "0.2.47",
3
+ "version": "0.2.49",
4
4
  "description": "Compiler facade for Frontier Lang source documents and language projection adapters.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",