@shapeshift-labs/frontier-lang-compiler 0.2.48 → 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
@@ -5,6 +5,7 @@ import {
5
5
  createSemanticImportSidecar,
6
6
  createSemanticSlice,
7
7
  createSemanticSliceAdmissionRecord,
8
+ createUniversalConversionPlan,
8
9
  projectNativeImportToSource,
9
10
  summarizeNativeImportFeatureEvidence,
10
11
  testSemanticSlice
@@ -47,6 +48,13 @@ export function measureNativeTransformations(nativeImportResults) {
47
48
  }));
48
49
  const sliceAdmissionDurationMs = performance.now() - sliceAdmissionStart;
49
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;
57
+
50
58
  const featureEvidenceStart = performance.now();
51
59
  const featureEvidenceSummaries = nativeImportResults.map((imported) => summarizeNativeImportFeatureEvidence(imported.losses, {
52
60
  evidence: imported.evidence
@@ -77,6 +85,9 @@ export function measureNativeTransformations(nativeImportResults) {
77
85
  sliceGateFailures,
78
86
  sliceAdmissions: semanticSliceAdmissions.length,
79
87
  sliceAdmissionRejected: semanticSliceAdmissions.filter((admission) => admission.action === 'reject').length,
88
+ conversionPlanRoutes: conversionPlan.routes.length,
89
+ conversionPlanBlocked: conversionPlan.summary.blockedRoutes,
90
+ conversionPlanDurationMs,
80
91
  featureEvidencePolicyMatches,
81
92
  featureEvidenceDurationMs,
82
93
  nativeProjections: nativeProjections.length,
package/bench/smoke.mjs CHANGED
@@ -57,6 +57,9 @@ console.log(JSON.stringify({
57
57
  sliceGateFailures: transformMetrics.sliceGateFailures,
58
58
  sliceAdmissions: transformMetrics.sliceAdmissions,
59
59
  sliceAdmissionRejected: transformMetrics.sliceAdmissionRejected,
60
+ conversionPlanRoutes: transformMetrics.conversionPlanRoutes,
61
+ conversionPlanBlocked: transformMetrics.conversionPlanBlocked,
62
+ conversionPlanDurationMs: Number(transformMetrics.conversionPlanDurationMs.toFixed(2)),
60
63
  featureEvidencePolicyMatches: transformMetrics.featureEvidencePolicyMatches,
61
64
  featureEvidenceDurationMs: Number(transformMetrics.featureEvidenceDurationMs.toFixed(2)),
62
65
  nativeProjections: transformMetrics.nativeProjections,
@@ -37,6 +37,7 @@ 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';
@@ -87,6 +88,11 @@ export declare function createNativeParserFeatureMatrix(options?: NativeParserFe
87
88
  export declare function queryNativeParserFeatureMatrix(matrixOrOptions?: NativeParserFeatureMatrix | NativeParserFeatureMatrixOptions, query?: NativeParserFeatureMatrixQuery): NativeParserFeatureMatrixQueryResult;
88
89
  export declare function createProjectionTargetLossMatrix(options?: ProjectionTargetLossMatrixOptions): ProjectionTargetLossMatrix;
89
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;
90
96
  export declare function createNativeSourcePreservation(options: CreateNativeSourcePreservationOptions): NativeSourcePreservation;
91
97
  export declare function createSemanticImportSidecar(importResult: NativeSourceImportResult | NativeProjectImportResult, options?: SemanticImportSidecarOptions): SemanticImportSidecar;
92
98
  export declare function createNativeImportResultContract(importResult: NativeSourceImportResult | NativeProjectImportResult, options?: NativeImportResultContractOptions): NativeImportResultContract;
@@ -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';
package/dist/index.js CHANGED
@@ -29,6 +29,7 @@ export { createTreeSitterNativeImporterAdapter } from './internal/index-impl/cre
29
29
  export { createTypeScriptCompilerNativeImporterAdapter } from './internal/index-impl/createTypeScriptCompilerNativeImporterAdapter.js';
30
30
  export { createUniversalAstFromDocument } from './internal/index-impl/createUniversalAstFromDocument.js';
31
31
  export { createUniversalCapabilityMatrix } from './internal/index-impl/createUniversalCapabilityMatrix.js';
32
+ export { createUniversalConversionPlan } from './internal/index-impl/createUniversalConversionPlan.js';
32
33
  export { attachUniversalDialectRegistry, createUniversalDialectRecord, createUniversalDialectRegistry, createUniversalExternRecord, summarizeUniversalDialectRegistry, UniversalDialectConstructKinds, UniversalDialectProjectionDispositions } from './universal-dialect-registry.js';
33
34
  export { diffNativeSourceImports } from './internal/index-impl/diffNativeSourceImports.js';
34
35
  export { diffNativeSources } from './internal/index-impl/diffNativeSources.js';
@@ -62,6 +63,7 @@ export { queryNativeParserFeatureMatrix } from './internal/index-impl/queryNativ
62
63
  export { queryProjectionReadinessMatrix } from './internal/index-impl/queryProjectionReadinessMatrix.js';
63
64
  export { createSemanticPatchBundleRecord, querySemanticPatchBundleRecords, SemanticPatchBundleAdmissionStatuses } from './internal/index-impl/semanticPatchBundleRecords.js';
64
65
  export { querySemanticMergeConflictClasses, SemanticMergeConflictClasses, semanticMergeConflictRiskScore, sortSemanticMergeCandidatesByConflictRisk, summarizeSemanticMergeConflicts } from './internal/index-impl/semanticMergeConflicts.js';
66
+ export { queryUniversalConversionPlan } from './internal/index-impl/queryUniversalConversionPlan.js';
65
67
  export { createSemanticHistoryRecord, querySemanticHistoryRecordOverlaps, SemanticHistoryAdmissionStatuses, SemanticHistoryConflictReasons, SemanticHistoryOverlapKinds, SemanticHistoryReviewerStatuses, semanticHistoryRecordsConflict, semanticHistoryRecordsOverlap } from './internal/index-impl/semanticHistoryRecords.js';
66
68
  export { readSemanticSliceJson } from './internal/index-impl/readSemanticSliceJson.js';
67
69
  export { readUniversalAstJson } from './internal/index-impl/readUniversalAstJson.js';
@@ -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.48",
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",