@shapeshift-labs/frontier-lang-compiler 0.2.21 → 0.2.22

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
@@ -64,6 +64,25 @@ console.log(readiness.readiness);
64
64
 
65
65
  The loss taxonomy separates broad scanner limits from specific round-trip risks such as conditional compilation, reflection, overload/type-inference gaps, comments/trivia preservation, source-map approximation, parser diagnostics, and target projection loss. These records are evidence labels for merge admission; they are not claims that the lightweight scanner expanded macros, evaluated inactive branches, resolved overloads, or ran a type checker.
66
66
 
67
+ High-risk native features also have explicit evidence policies. These policies are advisory in this package: they tell a swarm or admission queue what evidence is missing without silently changing the existing readiness classification.
68
+
69
+ ```js
70
+ import {
71
+ getNativeImportFeatureEvidencePolicy,
72
+ summarizeNativeImportFeatureEvidence
73
+ } from '@shapeshift-labs/frontier-lang-compiler';
74
+
75
+ const policy = getNativeImportFeatureEvidencePolicy('preprocessor');
76
+ console.log(policy.requiredEvidenceKeys); // ["preprocessedOutputHash", "definesHash"]
77
+
78
+ const featureEvidence = summarizeNativeImportFeatureEvidence(imported.losses, {
79
+ evidence: imported.evidence
80
+ });
81
+
82
+ console.log(featureEvidence.highestRisk);
83
+ console.log(featureEvidence.missingRequiredEvidence);
84
+ ```
85
+
67
86
  Ask the compiler what is actually covered before sending native imports into a merge queue:
68
87
 
69
88
  ```js
package/bench/smoke.mjs CHANGED
@@ -9,7 +9,8 @@ import {
9
9
  createSemanticImportSidecar,
10
10
  importNativeSource,
11
11
  projectNativeImportToSource,
12
- runNativeImporterAdapter
12
+ runNativeImporterAdapter,
13
+ summarizeNativeImportFeatureEvidence
13
14
  } from '../dist/index.js';
14
15
 
15
16
  const source = `
@@ -88,6 +89,13 @@ const semanticSidecars = nativeImportResults.map((imported) => createSemanticImp
88
89
  const sidecarDurationMs = performance.now() - sidecarStart;
89
90
  const sidecarOwnershipRegions = semanticSidecars.reduce((sum, sidecar) => sum + sidecar.ownershipRegions.length, 0);
90
91
 
92
+ const featureEvidenceStart = performance.now();
93
+ const featureEvidenceSummaries = nativeImportResults.map((imported) => summarizeNativeImportFeatureEvidence(imported.losses, {
94
+ evidence: imported.evidence
95
+ }));
96
+ const featureEvidenceDurationMs = performance.now() - featureEvidenceStart;
97
+ const featureEvidencePolicyMatches = featureEvidenceSummaries.reduce((sum, summary) => sum + summary.total, 0);
98
+
91
99
  const projectionStart = performance.now();
92
100
  const nativeProjections = nativeImportResults.map((imported) => projectNativeImportToSource(imported));
93
101
  const projectionDurationMs = performance.now() - projectionStart;
@@ -150,6 +158,8 @@ console.log(JSON.stringify({
150
158
  semanticSidecars: semanticSidecars.length,
151
159
  sidecarOwnershipRegions,
152
160
  sidecarDurationMs: Number(sidecarDurationMs.toFixed(2)),
161
+ featureEvidencePolicyMatches,
162
+ featureEvidenceDurationMs: Number(featureEvidenceDurationMs.toFixed(2)),
153
163
  nativeProjections: nativeProjections.length,
154
164
  projectionBytes,
155
165
  projectionDurationMs: Number(projectionDurationMs.toFixed(2)),
package/dist/index.d.ts CHANGED
@@ -151,6 +151,49 @@ export interface NativeImportLossSummaryOptions {
151
151
  readonly semanticStatus?: string;
152
152
  }
153
153
 
154
+ export type NativeImportFeatureEvidenceRisk = 'low' | 'medium' | 'high' | 'critical' | string;
155
+
156
+ export interface NativeImportFeatureEvidencePolicy {
157
+ readonly kind: NativeImportKnownLossKind;
158
+ readonly category: NativeImportTaxonomyKind;
159
+ readonly risk: NativeImportFeatureEvidenceRisk;
160
+ readonly minimumReadiness: SemanticMergeReadiness;
161
+ readonly missingEvidenceReadiness: SemanticMergeReadiness;
162
+ readonly requiredEvidenceKeys: readonly string[];
163
+ readonly recommendedEvidenceKeys: readonly string[];
164
+ readonly notes: readonly string[];
165
+ }
166
+
167
+ export interface NativeImportFeatureEvidenceIssue {
168
+ readonly lossId: string;
169
+ readonly kind: NativeImportKnownLossKind;
170
+ readonly policyKind: NativeImportKnownLossKind;
171
+ readonly risk: NativeImportFeatureEvidenceRisk;
172
+ readonly category: NativeImportTaxonomyKind;
173
+ readonly readiness: SemanticMergeReadiness;
174
+ readonly missingRequiredEvidence: readonly string[];
175
+ readonly presentRequiredEvidence: readonly string[];
176
+ readonly presentRecommendedEvidence: readonly string[];
177
+ readonly evidenceIds: readonly string[];
178
+ }
179
+
180
+ export interface NativeImportFeatureEvidenceSummary {
181
+ readonly total: number;
182
+ readonly policyKinds: readonly NativeImportKnownLossKind[];
183
+ readonly byKind: Readonly<Record<string, number>>;
184
+ readonly byRisk: Readonly<Record<string, number>>;
185
+ readonly highestRisk: NativeImportFeatureEvidenceRisk;
186
+ readonly semanticMergeReadiness: SemanticMergeReadiness;
187
+ readonly missingRequiredEvidence: readonly {
188
+ readonly lossId: string;
189
+ readonly kind: NativeImportKnownLossKind;
190
+ readonly policyKind: NativeImportKnownLossKind;
191
+ readonly evidenceKey: string;
192
+ }[];
193
+ readonly issues: readonly NativeImportFeatureEvidenceIssue[];
194
+ readonly reasons: readonly string[];
195
+ }
196
+
154
197
  export interface NativeImportLossSummary {
155
198
  readonly total: number;
156
199
  readonly hasLosses: boolean;
@@ -165,6 +208,7 @@ export interface NativeImportLossSummary {
165
208
  readonly reviewLossIds: readonly string[];
166
209
  readonly informationalLossIds: readonly string[];
167
210
  readonly failedEvidenceIds: readonly string[];
211
+ readonly featureEvidence: NativeImportFeatureEvidenceSummary;
168
212
  readonly parser?: string;
169
213
  readonly scanKind?: string;
170
214
  readonly semanticStatus?: string;
@@ -1428,6 +1472,7 @@ export declare const NativeImportLossKinds: readonly NativeImportKnownLossKind[]
1428
1472
  export declare const NativeImportRegionTaxonomyKinds: readonly NativeImportRegionTaxonomyKind[];
1429
1473
  export declare const ProjectionTargetLossClasses: readonly ProjectionTargetLossClass[];
1430
1474
  export declare const NativeImportReadinessBySeverity: Readonly<Record<NativeImportLossSummary['highestSeverity'], SemanticMergeReadiness>>;
1475
+ export declare const NativeImportFeatureEvidencePolicies: Readonly<Record<string, NativeImportFeatureEvidencePolicy>>;
1431
1476
  export declare const NativeImportLanguageProfiles: readonly NativeImportLanguageProfile[];
1432
1477
  export declare function normalizeCompileTarget(target?: string): FrontierCompileTarget;
1433
1478
  export declare function compileFrontierSource(source: string, options?: FrontierCompileOptions): FrontierCompileResult;
@@ -1438,6 +1483,8 @@ export declare function renderTargetAst(ast: FrontierTargetAst, target?: Frontie
1438
1483
  export declare function renderTargetAstWithSourceMap(ast: FrontierTargetAst, target?: FrontierCompileOptions['target'], options?: FrontierCompileEmitOptions): FrontierTargetSourceMapResult;
1439
1484
  export declare function emitForTargetWithSourceMap(document: FrontierLangDocument, target?: FrontierCompileOptions['target'], options?: FrontierCompileEmitOptions): FrontierTargetDocumentSourceMapResult;
1440
1485
  export declare function resolveCapabilityAdapters(document: FrontierLangDocument, target?: FrontierCompileOptions['target'], options?: { readonly platform?: string }): readonly CapabilityResolution[];
1486
+ export declare function getNativeImportFeatureEvidencePolicy(kind: NativeImportKnownLossKind | string): NativeImportFeatureEvidencePolicy | undefined;
1487
+ export declare function summarizeNativeImportFeatureEvidence(losses?: readonly NativeAstLossRecord[], options?: NativeImportLossSummaryOptions): NativeImportFeatureEvidenceSummary;
1441
1488
  export declare function summarizeNativeImportLosses(losses?: readonly NativeAstLossRecord[], options?: NativeImportLossSummaryOptions): NativeImportLossSummary;
1442
1489
  export declare function classifyNativeImportReadiness(losses?: readonly NativeAstLossRecord[], options?: NativeImportLossSummaryOptions): NativeImportReadinessClassification;
1443
1490
  export declare function classifyNativeImportRoundtripReadiness(importResult: NativeSourceImportResult | NativeProjectImportResult, options?: NativeImportRoundtripReadinessOptions): NativeImportRoundtripReadinessClassification;
package/dist/index.js CHANGED
@@ -76,6 +76,13 @@ const semanticMergeReadinessRank = Object.freeze({
76
76
  blocked: 3
77
77
  });
78
78
 
79
+ const nativeFeatureEvidenceRiskRank = Object.freeze({
80
+ low: 0,
81
+ medium: 1,
82
+ high: 2,
83
+ critical: 3
84
+ });
85
+
79
86
  export const NativeImportRoundtripReadinessStatuses = Object.freeze([
80
87
  'exact',
81
88
  'preserved-source',
@@ -136,6 +143,117 @@ export const NativeImportReadinessBySeverity = Object.freeze({
136
143
  error: 'blocked'
137
144
  });
138
145
 
146
+ export const NativeImportFeatureEvidencePolicies = Object.freeze({
147
+ macroExpansion: nativeImportFeatureEvidencePolicy('macroExpansion', {
148
+ category: 'macroExpansion',
149
+ risk: 'high',
150
+ minimumReadiness: 'needs-review',
151
+ requiredEvidenceKeys: ['macroDefinitionsHash', 'expandedSourceHash'],
152
+ recommendedEvidenceKeys: ['expansionMapId', 'sourceMapId', 'macroCallSites'],
153
+ notes: ['Macro-expanded code must retain a link from generated output back to macro call sites before semantic merges can be trusted.']
154
+ }),
155
+ macroHygiene: nativeImportFeatureEvidencePolicy('macroHygiene', {
156
+ category: 'macroExpansion',
157
+ risk: 'critical',
158
+ minimumReadiness: 'needs-review',
159
+ missingEvidenceReadiness: 'blocked',
160
+ requiredEvidenceKeys: ['hygieneContextHash', 'bindingMapId'],
161
+ recommendedEvidenceKeys: ['expansionMapId', 'captureSetHash'],
162
+ notes: ['Hygiene-sensitive macros can change binding identity even when emitted text looks equivalent.']
163
+ }),
164
+ preprocessor: nativeImportFeatureEvidencePolicy('preprocessor', {
165
+ category: 'preprocessor',
166
+ risk: 'high',
167
+ minimumReadiness: 'needs-review',
168
+ requiredEvidenceKeys: ['preprocessedOutputHash', 'definesHash'],
169
+ recommendedEvidenceKeys: ['includeGraphHash', 'conditionalBranches', 'sourceMapId'],
170
+ notes: ['Preprocessor imports need the active defines/includes and preprocessed output hash to make replayable claims.']
171
+ }),
172
+ conditionalCompilation: nativeImportFeatureEvidencePolicy('conditionalCompilation', {
173
+ category: 'conditionalCompilation',
174
+ risk: 'high',
175
+ minimumReadiness: 'needs-review',
176
+ requiredEvidenceKeys: ['activeBranches', 'inactiveBranchesHash'],
177
+ recommendedEvidenceKeys: ['compileTarget', 'featureFlags', 'preprocessedOutputHash'],
178
+ notes: ['Conditional branches that were not active still affect portability and conflict review.']
179
+ }),
180
+ metaprogramming: nativeImportFeatureEvidencePolicy('metaprogramming', {
181
+ category: 'metaprogramming',
182
+ risk: 'critical',
183
+ minimumReadiness: 'needs-review',
184
+ missingEvidenceReadiness: 'blocked',
185
+ requiredEvidenceKeys: ['generatedArtifactHash', 'generatorIdentity'],
186
+ recommendedEvidenceKeys: ['generatorInputsHash', 'generatedRanges', 'replayCommand'],
187
+ notes: ['Generated or metaprogrammed declarations need replayable generator identity and input evidence.']
188
+ }),
189
+ reflection: nativeImportFeatureEvidencePolicy('reflection', {
190
+ category: 'reflection',
191
+ risk: 'high',
192
+ minimumReadiness: 'needs-review',
193
+ requiredEvidenceKeys: ['reflectionSurface', 'runtimeContract'],
194
+ recommendedEvidenceKeys: ['observedMembers', 'fixtureIds', 'runtimeVersion'],
195
+ notes: ['Reflection-heavy code needs a declared runtime contract because static AST evidence is incomplete.']
196
+ }),
197
+ dynamicRuntime: nativeImportFeatureEvidencePolicy('dynamicRuntime', {
198
+ category: 'reflection',
199
+ risk: 'high',
200
+ minimumReadiness: 'needs-review',
201
+ requiredEvidenceKeys: ['runtimeContract'],
202
+ recommendedEvidenceKeys: ['fixtureIds', 'observedEffects', 'runtimeVersion'],
203
+ notes: ['Dynamic runtime behavior should stay review-required until fixtures or traces describe the observed contract.']
204
+ }),
205
+ dynamicDispatch: nativeImportFeatureEvidencePolicy('dynamicDispatch', {
206
+ category: 'overloadTypeInference',
207
+ risk: 'medium',
208
+ minimumReadiness: 'needs-review',
209
+ requiredEvidenceKeys: ['dispatchTargets'],
210
+ recommendedEvidenceKeys: ['callGraphId', 'typeEvidenceId', 'fixtureIds'],
211
+ notes: ['Dynamic dispatch needs candidate target evidence before call graph or porting claims are merge-ready.']
212
+ }),
213
+ generatedCode: nativeImportFeatureEvidencePolicy('generatedCode', {
214
+ category: 'generatedCode',
215
+ risk: 'high',
216
+ minimumReadiness: 'needs-review',
217
+ requiredEvidenceKeys: ['generatedArtifactHash', 'generatedRanges'],
218
+ recommendedEvidenceKeys: ['generatorIdentity', 'generatorInputsHash', 'sourceMapId'],
219
+ notes: ['Generated code must preserve generated ranges and artifact hashes so workers can avoid editing derived output blindly.']
220
+ }),
221
+ overloadResolution: nativeImportFeatureEvidencePolicy('overloadResolution', {
222
+ category: 'overloadTypeInference',
223
+ risk: 'medium',
224
+ minimumReadiness: 'needs-review',
225
+ requiredEvidenceKeys: ['resolvedOverloads'],
226
+ recommendedEvidenceKeys: ['typeEvidenceId', 'compilerVersion', 'callSiteSpans'],
227
+ notes: ['Overload-sensitive imports should record compiler/type evidence for each call site.']
228
+ }),
229
+ typeInference: nativeImportFeatureEvidencePolicy('typeInference', {
230
+ category: 'overloadTypeInference',
231
+ risk: 'medium',
232
+ minimumReadiness: 'needs-review',
233
+ requiredEvidenceKeys: ['inferredTypesHash'],
234
+ recommendedEvidenceKeys: ['typeEvidenceId', 'compilerVersion', 'symbolTableHash'],
235
+ notes: ['Inferred types need a stable type-evidence hash before cross-language projection can claim fidelity.']
236
+ }),
237
+ unsupportedSyntax: nativeImportFeatureEvidencePolicy('unsupportedSyntax', {
238
+ category: 'unsupportedSyntax',
239
+ risk: 'high',
240
+ minimumReadiness: 'needs-review',
241
+ missingEvidenceReadiness: 'blocked',
242
+ requiredEvidenceKeys: ['unsupportedSyntaxKind', 'sourceSpan'],
243
+ recommendedEvidenceKeys: ['parserDiagnosticId', 'nativeAstNodeId', 'sourceSnippetHash'],
244
+ notes: ['Unsupported syntax must remain anchored to source spans and parser diagnostics for later adapter work.']
245
+ }),
246
+ unsupportedSemantic: nativeImportFeatureEvidencePolicy('unsupportedSemantic', {
247
+ category: 'unsupportedSyntax',
248
+ risk: 'high',
249
+ minimumReadiness: 'needs-review',
250
+ missingEvidenceReadiness: 'blocked',
251
+ requiredEvidenceKeys: ['unsupportedSemanticKind', 'semanticSymbolId'],
252
+ recommendedEvidenceKeys: ['semanticIndexId', 'sourceMapId', 'reason'],
253
+ notes: ['Unsupported semantics should name the affected symbol so merge tools can isolate the unsafe region.']
254
+ })
255
+ });
256
+
139
257
  export const NativeImportRegionTaxonomyKinds = Object.freeze([
140
258
  'symbol',
141
259
  'declaration',
@@ -473,6 +591,70 @@ export function resolveCapabilityAdapters(document, target = 'typescript', optio
473
591
  });
474
592
  }
475
593
 
594
+ export function getNativeImportFeatureEvidencePolicy(kind) {
595
+ const normalized = normalizeNativeLossKind({ kind }, 'warning');
596
+ return NativeImportFeatureEvidencePolicies[normalized] ?? NativeImportFeatureEvidencePolicies[String(kind ?? '')];
597
+ }
598
+
599
+ export function summarizeNativeImportFeatureEvidence(losses = [], options = {}) {
600
+ const normalizedLosses = normalizeNativeLossRecords(losses);
601
+ const evidence = options.evidence ?? [];
602
+ const issues = [];
603
+ const byKind = {};
604
+ const byRisk = {};
605
+ const policyKinds = [];
606
+ let highestRisk = 'low';
607
+ let semanticMergeReadiness = 'ready';
608
+
609
+ for (const loss of normalizedLosses) {
610
+ const policy = getNativeImportFeatureEvidencePolicy(loss.kind);
611
+ if (!policy) continue;
612
+ byKind[policy.kind] = (byKind[policy.kind] ?? 0) + 1;
613
+ byRisk[policy.risk] = (byRisk[policy.risk] ?? 0) + 1;
614
+ if ((nativeFeatureEvidenceRiskRank[policy.risk] ?? 0) > (nativeFeatureEvidenceRiskRank[highestRisk] ?? 0)) {
615
+ highestRisk = policy.risk;
616
+ }
617
+ policyKinds.push(policy.kind);
618
+ semanticMergeReadiness = maxSemanticMergeReadiness(semanticMergeReadiness, policy.minimumReadiness);
619
+ const missingRequiredEvidence = policy.requiredEvidenceKeys.filter((key) => !nativeImportFeatureEvidenceHasKey(loss, evidence, key));
620
+ const presentRequiredEvidence = policy.requiredEvidenceKeys.filter((key) => !missingRequiredEvidence.includes(key));
621
+ const presentRecommendedEvidence = policy.recommendedEvidenceKeys.filter((key) => nativeImportFeatureEvidenceHasKey(loss, evidence, key));
622
+ if (missingRequiredEvidence.length) {
623
+ semanticMergeReadiness = maxSemanticMergeReadiness(semanticMergeReadiness, policy.missingEvidenceReadiness);
624
+ }
625
+ issues.push({
626
+ lossId: loss.id,
627
+ kind: loss.kind,
628
+ policyKind: policy.kind,
629
+ risk: policy.risk,
630
+ category: policy.category,
631
+ readiness: missingRequiredEvidence.length ? policy.missingEvidenceReadiness : policy.minimumReadiness,
632
+ missingRequiredEvidence,
633
+ presentRequiredEvidence,
634
+ presentRecommendedEvidence,
635
+ evidenceIds: nativeImportFeatureEvidenceIds(loss, evidence, policy)
636
+ });
637
+ }
638
+
639
+ const missingRequiredEvidence = issues.flatMap((issue) => issue.missingRequiredEvidence.map((key) => ({
640
+ lossId: issue.lossId,
641
+ kind: issue.kind,
642
+ policyKind: issue.policyKind,
643
+ evidenceKey: key
644
+ })));
645
+ return {
646
+ total: issues.length,
647
+ policyKinds: uniqueStrings(policyKinds),
648
+ byKind,
649
+ byRisk,
650
+ highestRisk: issues.length ? highestRisk : 'low',
651
+ semanticMergeReadiness,
652
+ missingRequiredEvidence,
653
+ issues,
654
+ reasons: nativeImportFeatureEvidenceReasons(issues)
655
+ };
656
+ }
657
+
476
658
  export function summarizeNativeImportLosses(losses = [], options = {}) {
477
659
  const normalizedLosses = normalizeNativeLossRecords(losses);
478
660
  const bySeverity = { info: 0, warning: 0, error: 0 };
@@ -512,6 +694,9 @@ export function summarizeNativeImportLosses(losses = [], options = {}) {
512
694
  reviewLossIds,
513
695
  informationalLossIds
514
696
  });
697
+ const featureEvidence = summarizeNativeImportFeatureEvidence(normalizedLosses, {
698
+ evidence: options.evidence
699
+ });
515
700
 
516
701
  return {
517
702
  total: normalizedLosses.length,
@@ -527,6 +712,7 @@ export function summarizeNativeImportLosses(losses = [], options = {}) {
527
712
  reviewLossIds,
528
713
  informationalLossIds,
529
714
  failedEvidenceIds,
715
+ featureEvidence,
530
716
  parser: options.parser,
531
717
  scanKind: options.scanKind,
532
718
  semanticStatus: options.semanticStatus
@@ -4112,6 +4298,61 @@ function nativeImportCategoryForLossKind(kind) {
4112
4298
  return String(kind ?? 'opaqueNative');
4113
4299
  }
4114
4300
 
4301
+ function nativeImportFeatureEvidencePolicy(kind, input = {}) {
4302
+ return Object.freeze({
4303
+ kind,
4304
+ category: input.category ?? nativeImportCategoryForLossKind(kind),
4305
+ risk: input.risk ?? 'medium',
4306
+ minimumReadiness: normalizeSemanticMergeReadiness(input.minimumReadiness) ?? 'needs-review',
4307
+ missingEvidenceReadiness: normalizeSemanticMergeReadiness(input.missingEvidenceReadiness) ?? 'needs-review',
4308
+ requiredEvidenceKeys: Object.freeze(uniqueStrings(input.requiredEvidenceKeys ?? [])),
4309
+ recommendedEvidenceKeys: Object.freeze(uniqueStrings(input.recommendedEvidenceKeys ?? [])),
4310
+ notes: Object.freeze(uniqueStrings(input.notes ?? []))
4311
+ });
4312
+ }
4313
+
4314
+ function nativeImportFeatureEvidenceHasKey(loss, evidence, key) {
4315
+ return nativeImportFeatureEvidenceValuePresent(nativeImportFeatureEvidenceValue(loss, key))
4316
+ || (evidence ?? []).some((record) => nativeImportFeatureEvidenceValuePresent(nativeImportFeatureEvidenceValue(record, key)));
4317
+ }
4318
+
4319
+ function nativeImportFeatureEvidenceValue(record, key) {
4320
+ if (!record || !key) return undefined;
4321
+ const candidates = [record, record.metadata].filter(Boolean);
4322
+ for (const candidate of candidates) {
4323
+ const direct = candidate[key];
4324
+ if (direct !== undefined) return direct;
4325
+ const dotted = String(key).split('.').reduce((current, part) => current?.[part], candidate);
4326
+ if (dotted !== undefined) return dotted;
4327
+ }
4328
+ return undefined;
4329
+ }
4330
+
4331
+ function nativeImportFeatureEvidenceValuePresent(value) {
4332
+ if (value === undefined || value === null) return false;
4333
+ if (typeof value === 'string') return value.trim().length > 0;
4334
+ if (Array.isArray(value)) return value.length > 0;
4335
+ if (typeof value === 'object') return Object.keys(value).length > 0;
4336
+ return true;
4337
+ }
4338
+
4339
+ function nativeImportFeatureEvidenceIds(loss, evidence, policy) {
4340
+ const keys = [...policy.requiredEvidenceKeys, ...policy.recommendedEvidenceKeys];
4341
+ return uniqueStrings((evidence ?? [])
4342
+ .filter((record) => keys.some((key) => nativeImportFeatureEvidenceValuePresent(nativeImportFeatureEvidenceValue(record, key))))
4343
+ .map((record) => record.id)
4344
+ .filter(Boolean)
4345
+ .concat(loss.evidenceIds ?? []));
4346
+ }
4347
+
4348
+ function nativeImportFeatureEvidenceReasons(issues) {
4349
+ return uniqueStrings((issues ?? []).flatMap((issue) => {
4350
+ const missing = issue.missingRequiredEvidence ?? [];
4351
+ if (!missing.length) return [];
4352
+ return [`${issue.kind} loss ${issue.lossId} is missing required evidence: ${missing.join(', ')}.`];
4353
+ }));
4354
+ }
4355
+
4115
4356
  function normalizeProjectionMatrixTargets(targets) {
4116
4357
  return uniqueStrings((Array.isArray(targets) ? targets : [targets])
4117
4358
  .map((target) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shapeshift-labs/frontier-lang-compiler",
3
- "version": "0.2.21",
3
+ "version": "0.2.22",
4
4
  "description": "Compiler facade for Frontier Lang source documents and language projection adapters.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",