@shapeshift-labs/frontier-swarm-codex 0.5.35 → 0.5.37

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/dist/index.js CHANGED
@@ -336,6 +336,7 @@ export async function runCodexJob(job, options, outDir, lease) {
336
336
  evidenceDir: paths.evidenceDir,
337
337
  options: options.semanticImport
338
338
  });
339
+ const semanticImportSummary = semanticImport?.sidecar.summary;
339
340
  const handoffArtifacts = await discoverCodexHandoffArtifacts({ root: paths.jobDir });
340
341
  const evidenceSummaryPath = path.join(paths.evidenceDir, 'evidence.json');
341
342
  const evidencePaths = uniqueStrings([
@@ -364,14 +365,14 @@ export async function runCodexJob(job, options, outDir, lease) {
364
365
  ...(patchPath ? { patchPath } : {}),
365
366
  queueItemIds: [job.taskId],
366
367
  verification,
367
- ...(semanticImport ? { semanticImport: semanticImport.sidecar.summary } : {}),
368
+ ...(semanticImportSummary ? { semanticImport: semanticImportSummary } : {}),
368
369
  lastMessage: execution.lastMessage,
369
370
  error: execution.error,
370
371
  metadata: {
371
372
  ...(lease ? { leaseId: lease.id, leaseToken: lease.token, fencingToken: lease.fencingToken } : {}),
372
373
  resourceAllocation,
373
374
  logSummary,
374
- ...(semanticImport ? { semanticImport: semanticImport.sidecar.summary } : {}),
375
+ ...(semanticImportSummary ? { semanticImport: semanticImportSummary } : {}),
375
376
  codexHandoffArtifacts: handoffArtifacts
376
377
  }
377
378
  };
@@ -391,9 +392,16 @@ export async function runCodexJob(job, options, outDir, lease) {
391
392
  ...handoffArtifacts.map((artifact) => artifact.path)
392
393
  ]),
393
394
  queueItemIds: [job.taskId],
394
- ...(semanticImport ? { semanticImport: semanticImport.sidecar.summary } : {}),
395
- ...(semanticImport ? { metadata: { semanticImport: semanticImport.sidecar.summary } } : {})
395
+ ...(semanticImportSummary ? { semanticImport: semanticImportSummary } : {}),
396
+ ...(semanticImportSummary ? { metadata: { semanticImport: semanticImportSummary } } : {})
396
397
  });
398
+ if (semanticImportSummary) {
399
+ mergeBundle.semanticImport = semanticImportSummary;
400
+ mergeBundle.metadata = {
401
+ ...(isObject(mergeBundle.metadata) ? mergeBundle.metadata : {}),
402
+ semanticImport: semanticImportSummary
403
+ };
404
+ }
397
405
  await fs.writeFile(paths.mergeBundlePath, JSON.stringify(mergeBundle, null, 2) + '\n');
398
406
  await writeCodexPatchIntent({
399
407
  file: paths.patchIntentPath,
@@ -650,6 +658,8 @@ async function createCodexSemanticImportSidecar(input) {
650
658
  losses: summarizeSemanticLosses(importResult?.losses),
651
659
  semanticIndex: summarizeSemanticIndex(importResult?.semanticIndex),
652
660
  semanticSidecar: summarizeLangSemanticImportSidecar(semanticSidecar),
661
+ universalAstLayers: summarizeUniversalAstLayers(importResult?.universalAst, semanticSidecar),
662
+ proofSpec: summarizeProofSpec(importResult?.universalAst?.proof, semanticSidecar),
653
663
  sourceProjection: summarizeNativeSourceProjection(sourceProjection),
654
664
  nativeCompile: summarizeNativeSourceCompile(nativeCompile),
655
665
  mergeCandidate: summarizeSemanticMergeCandidate(mergeCandidate)
@@ -1472,6 +1482,7 @@ async function copyOrWriteCollectedEvidenceSummary(input) {
1472
1482
  }
1473
1483
  function createCollectedEvidenceEntries(bundle, collectedEvidencePath, bucket) {
1474
1484
  const confidence = bucket === 'ready-to-apply' ? 0.95 : bucket === 'needs-human-port' ? 0.7 : bucket === 'failed-evidence' ? 0.25 : 0.2;
1485
+ const universalAstLayers = semanticImportUniversalAstLayerSummary(bundle.semanticImport);
1475
1486
  const entries = [{
1476
1487
  jobId: bundle.jobId,
1477
1488
  queueItemId: bundle.queueItemIds[0],
@@ -1489,7 +1500,11 @@ function createCollectedEvidenceEntries(bundle, collectedEvidencePath, bucket) {
1489
1500
  autoMergeable: bundle.autoMergeable,
1490
1501
  staleAgainstHead: bundle.staleAgainstHead,
1491
1502
  semanticSymbols: bundle.semanticImport?.semanticIndex.symbols ?? 0,
1492
- semanticRegions: bundle.semanticImport?.semanticSidecars.ownershipRegions ?? 0
1503
+ semanticRegions: bundle.semanticImport?.semanticSidecars.ownershipRegions ?? 0,
1504
+ universalAstLayers: universalAstLayers.total,
1505
+ universalAstLayerNames: universalAstLayers.names.join(','),
1506
+ proofSpecObligations: semanticImportProofSpecSummary(bundle.semanticImport).obligations,
1507
+ proofSpecFailedObligations: semanticImportProofSpecSummary(bundle.semanticImport).failed
1493
1508
  }
1494
1509
  }];
1495
1510
  for (const file of bundle.evidencePaths) {
@@ -1551,7 +1566,11 @@ function createCodexCompactDashboard(input) {
1551
1566
  weakCount: semanticQualities.filter((entry) => entry.present && entry.warnings.length > 0).length,
1552
1567
  symbolCount: semanticQualities.reduce((sum, entry) => sum + entry.symbols, 0),
1553
1568
  ownershipRegionCount: semanticQualities.reduce((sum, entry) => sum + entry.ownershipRegions, 0),
1554
- patchHintCount: semanticQualities.reduce((sum, entry) => sum + entry.patchHints, 0)
1569
+ patchHintCount: semanticQualities.reduce((sum, entry) => sum + entry.patchHints, 0),
1570
+ universalAstLayerCount: semanticQualities.reduce((sum, entry) => sum + entry.universalAstLayers, 0),
1571
+ universalAstLayerNames: uniqueStrings(semanticQualities.flatMap((entry) => entry.universalAstLayerNames)),
1572
+ proofSpecObligations: semanticQualities.reduce((sum, entry) => sum + entry.proofSpecObligations, 0),
1573
+ proofSpecFailedObligations: semanticQualities.reduce((sum, entry) => sum + entry.proofSpecFailedObligations, 0)
1555
1574
  },
1556
1575
  evidence: {
1557
1576
  readyToApply: input.dashboard.summary.readyToApplyCount,
@@ -1800,6 +1819,10 @@ function summarizePatchScoreSemanticEvidence(bundle) {
1800
1819
  semanticSymbols: 0,
1801
1820
  ownershipRegions: 0,
1802
1821
  patchHints: 0,
1822
+ universalAstLayers: 0,
1823
+ universalAstLayerNames: [],
1824
+ proofSpecObligations: 0,
1825
+ proofSpecFailedObligations: 0,
1803
1826
  readiness: {},
1804
1827
  lossesBySeverity: {},
1805
1828
  scoreAdjustment,
@@ -1817,6 +1840,10 @@ function summarizePatchScoreSemanticEvidence(bundle) {
1817
1840
  const semanticSymbols = nonNegativeNumber(summary.semanticIndex?.symbols);
1818
1841
  const ownershipRegions = nonNegativeNumber(summary.semanticSidecars?.ownershipRegions);
1819
1842
  const patchHints = nonNegativeNumber(summary.semanticSidecars?.patchHints);
1843
+ const universalAstLayerSummary = semanticImportUniversalAstLayerSummary(summary);
1844
+ const universalAstLayers = universalAstLayerSummary.total;
1845
+ const universalAstLayerNames = universalAstLayerSummary.names;
1846
+ const proofSpec = semanticImportProofSpecSummary(summary);
1820
1847
  const errorLosses = nonNegativeNumber(lossesBySeverity.error);
1821
1848
  const warningLosses = nonNegativeNumber(lossesBySeverity.warning);
1822
1849
  const blocked = nonNegativeNumber(readiness.blocked);
@@ -1856,16 +1883,39 @@ function summarizePatchScoreSemanticEvidence(bundle) {
1856
1883
  scoreAdjustment -= 5;
1857
1884
  cleanEligible = false;
1858
1885
  }
1886
+ if (selected > 0 && universalAstLayers === 0) {
1887
+ reasons.push('semantic sidecar has no universal AST layers');
1888
+ scoreAdjustment -= 5;
1889
+ cleanEligible = false;
1890
+ }
1859
1891
  if (warningLosses > 0 || needsReview > 0) {
1860
1892
  reasons.push('semantic evidence needs review');
1861
1893
  scoreAdjustment -= Math.min(10, warningLosses + needsReview);
1862
1894
  cleanEligible = false;
1863
1895
  }
1864
- if (sourceMapMappings > 0 && semanticSymbols > 0 && ownershipRegions > 0) {
1896
+ if (proofSpec.failed > 0) {
1897
+ reasons.push(`failed proof obligations: ${proofSpec.failed}`);
1898
+ scoreAdjustment -= 30;
1899
+ cleanEligible = false;
1900
+ }
1901
+ if (proofSpec.stale > 0) {
1902
+ reasons.push(`stale proof obligations: ${proofSpec.stale}`);
1903
+ scoreAdjustment -= 20;
1904
+ cleanEligible = false;
1905
+ }
1906
+ if (proofSpec.open > 0 || proofSpec.unknown > 0) {
1907
+ reasons.push('proof evidence needs review');
1908
+ scoreAdjustment -= Math.min(10, proofSpec.open + proofSpec.unknown);
1909
+ cleanEligible = false;
1910
+ }
1911
+ if (sourceMapMappings > 0 && semanticSymbols > 0 && ownershipRegions > 0 && universalAstLayers > 0) {
1865
1912
  scoreAdjustment += 10;
1866
1913
  }
1867
1914
  if (patchHints > 0)
1868
1915
  scoreAdjustment += 5;
1916
+ if (proofSpec.discharged > 0 && proofSpec.failed === 0 && proofSpec.stale === 0 && proofSpec.open === 0 && proofSpec.unknown === 0) {
1917
+ scoreAdjustment += 5;
1918
+ }
1869
1919
  return {
1870
1920
  present: true,
1871
1921
  total,
@@ -1875,6 +1925,10 @@ function summarizePatchScoreSemanticEvidence(bundle) {
1875
1925
  semanticSymbols,
1876
1926
  ownershipRegions,
1877
1927
  patchHints,
1928
+ universalAstLayers,
1929
+ universalAstLayerNames,
1930
+ proofSpecObligations: proofSpec.obligations,
1931
+ proofSpecFailedObligations: proofSpec.failed,
1878
1932
  readiness,
1879
1933
  lossesBySeverity,
1880
1934
  scoreAdjustment: Math.max(-60, Math.min(15, scoreAdjustment)),
@@ -1890,6 +1944,10 @@ function summarizeCodexSemanticImportQuality(summary, expected = false) {
1890
1944
  const ownershipRegions = nonNegativeNumber(summary?.semanticSidecars?.ownershipRegions);
1891
1945
  const patchHints = nonNegativeNumber(summary?.semanticSidecars?.patchHints);
1892
1946
  const sourceMapMappings = nonNegativeNumber(summary?.sourceMapMappingCount);
1947
+ const universalAstLayerSummary = semanticImportUniversalAstLayerSummary(summary);
1948
+ const universalAstLayers = universalAstLayerSummary.total;
1949
+ const universalAstLayerNames = universalAstLayerSummary.names;
1950
+ const proofSpec = semanticImportProofSpecSummary(summary);
1893
1951
  const present = !!summary;
1894
1952
  const empty = present && (nonNegativeNumber(summary?.total) === 0 || selected === 0 && eligible === 0 && imported === 0 && symbols === 0);
1895
1953
  const warnings = [];
@@ -1905,6 +1963,12 @@ function summarizeCodexSemanticImportQuality(summary, expected = false) {
1905
1963
  warnings.push('semantic import has no ownership regions');
1906
1964
  if (present && selected > 0 && sourceMapMappings === 0)
1907
1965
  warnings.push('semantic import has no source-map mappings');
1966
+ if (present && selected > 0 && universalAstLayers === 0)
1967
+ warnings.push('semantic import has no universal AST layers');
1968
+ if (present && proofSpec.failed > 0)
1969
+ warnings.push('semantic import has failed proof obligations');
1970
+ if (present && proofSpec.stale > 0)
1971
+ warnings.push('semantic import has stale proof obligations');
1908
1972
  return {
1909
1973
  expected,
1910
1974
  present,
@@ -1916,14 +1980,60 @@ function summarizeCodexSemanticImportQuality(summary, expected = false) {
1916
1980
  ownershipRegions,
1917
1981
  patchHints,
1918
1982
  sourceMapMappings,
1983
+ universalAstLayers,
1984
+ universalAstLayerNames,
1985
+ proofSpecObligations: proofSpec.obligations,
1986
+ proofSpecFailedObligations: proofSpec.failed,
1919
1987
  warnings: uniqueStrings(warnings)
1920
1988
  };
1921
1989
  }
1990
+ function semanticImportProofSpecSummary(summary) {
1991
+ const input = isObject(summary) && isObject(summary.proofSpec) ? summary.proofSpec : undefined;
1992
+ return input ? normalizeProofSpecSummary(input) : emptyProofSpecSummary();
1993
+ }
1994
+ function semanticImportUniversalAstLayerSummary(summary) {
1995
+ const input = isObject(summary) && isObject(summary.universalAstLayers) ? summary.universalAstLayers : undefined;
1996
+ const names = Array.isArray(input?.names)
1997
+ ? uniqueStrings(input.names.map((entry) => String(entry)).filter(Boolean))
1998
+ : [];
1999
+ const ids = Array.isArray(input?.ids)
2000
+ ? uniqueStrings(input.ids.map((entry) => String(entry)).filter(Boolean))
2001
+ : [];
2002
+ const byName = isObject(input?.byName) ? numberRecord(input.byName) : {};
2003
+ const total = nonNegativeNumber(input?.total ?? ids.length);
2004
+ return {
2005
+ total,
2006
+ names,
2007
+ ids,
2008
+ byName,
2009
+ empty: input?.empty === true || total === 0
2010
+ };
2011
+ }
1922
2012
  function semanticImportSummaryFromBundle(bundle) {
1923
- if (bundle.semanticImport)
1924
- return bundle.semanticImport;
1925
2013
  const metadata = bundle.metadata;
1926
- return metadata?.semanticImport;
2014
+ return richerSemanticImportSummary(bundle.semanticImport, metadata?.semanticImport);
2015
+ }
2016
+ function richerSemanticImportSummary(first, second) {
2017
+ if (!first)
2018
+ return second;
2019
+ if (!second)
2020
+ return first;
2021
+ return semanticImportSummaryRichness(second) > semanticImportSummaryRichness(first) ? second : first;
2022
+ }
2023
+ function semanticImportSummaryRichness(summary) {
2024
+ if (!summary)
2025
+ return 0;
2026
+ return [
2027
+ summary.total,
2028
+ summary.selected,
2029
+ summary.imported,
2030
+ summary.sourceMapMappingCount,
2031
+ summary.semanticIndex?.symbols,
2032
+ summary.semanticSidecars?.ownershipRegions,
2033
+ summary.semanticSidecars?.patchHints,
2034
+ semanticImportUniversalAstLayerSummary(summary).total,
2035
+ semanticImportProofSpecSummary(summary).total
2036
+ ].reduce((sum, value) => sum + nonNegativeNumber(value), 0);
1927
2037
  }
1928
2038
  function semanticImportEnabled(input) {
1929
2039
  if (input === true)
@@ -2618,6 +2728,7 @@ function createSemanticImportSidecar(job, records, selection) {
2618
2728
  totals.empty += 1;
2619
2729
  return totals;
2620
2730
  }, { total: 0, symbols: 0, ownershipRegions: 0, patchHints: 0, empty: 0 });
2731
+ const universalAstLayers = summarizeSemanticImportUniversalAstLayers(records);
2621
2732
  const sourceProjections = records.reduce((totals, record) => {
2622
2733
  const summary = record.sourceProjection;
2623
2734
  if (!summary)
@@ -2654,6 +2765,7 @@ function createSemanticImportSidecar(job, records, selection) {
2654
2765
  totals.needsReview += 1;
2655
2766
  return totals;
2656
2767
  }, { total: 0, emitted: 0, preserved: 0, targetStubs: 0, ready: 0, needsReview: 0, blocked: 0 });
2768
+ const proofSpec = summarizeSemanticImportProofSpec(records);
2657
2769
  const lossesBySeverity = {};
2658
2770
  const readiness = {};
2659
2771
  for (const record of records) {
@@ -2689,6 +2801,8 @@ function createSemanticImportSidecar(job, records, selection) {
2689
2801
  lossesBySeverity,
2690
2802
  semanticIndex,
2691
2803
  semanticSidecars,
2804
+ universalAstLayers,
2805
+ proofSpec,
2692
2806
  sourceProjections,
2693
2807
  nativeCompiles,
2694
2808
  readiness
@@ -2716,6 +2830,13 @@ function summarizeLangSemanticImportSidecar(value) {
2716
2830
  symbols: value.summary?.symbols,
2717
2831
  ownershipRegions: value.summary?.ownershipRegions,
2718
2832
  sourceMapMappings: value.summary?.sourceMapMappings,
2833
+ universalAstLayers: value.summary?.universalAstLayers ?? value.universalAstLayers?.total,
2834
+ universalAstLayerNames: Array.isArray(value.summary?.universalAstLayerNames)
2835
+ ? value.summary.universalAstLayerNames
2836
+ : Array.isArray(value.universalAstLayers?.names)
2837
+ ? value.universalAstLayers.names
2838
+ : [],
2839
+ proofSpec: summarizeProofSpec(undefined, value),
2719
2840
  readiness: value.summary?.readiness,
2720
2841
  emptySemanticIndex: value.summary?.emptySemanticIndex,
2721
2842
  patchHints: Array.isArray(value.patchHints) ? value.patchHints.length : 0,
@@ -2732,6 +2853,200 @@ function summarizeLangSemanticImportSidecar(value) {
2732
2853
  : []
2733
2854
  };
2734
2855
  }
2856
+ function summarizeSemanticImportProofSpec(records) {
2857
+ const summary = emptyProofSpecSummary();
2858
+ for (const record of records) {
2859
+ mergeProofSpecSummary(summary, record.proofSpec);
2860
+ }
2861
+ summary.empty = summary.total === 0;
2862
+ return summary;
2863
+ }
2864
+ function summarizeProofSpec(proof, semanticSidecar) {
2865
+ const sidecarProof = semanticSidecar?.proofSpec ?? semanticSidecar?.summary?.proofSpec;
2866
+ if (sidecarProof && typeof sidecarProof === 'object' && hasProofSpecSummaryShape(sidecarProof)) {
2867
+ return normalizeProofSpecSummary(sidecarProof);
2868
+ }
2869
+ const raw = proof && typeof proof === 'object' ? proof : {};
2870
+ const contracts = Array.isArray(raw.contracts) ? raw.contracts : [];
2871
+ const refinements = Array.isArray(raw.refinements) ? raw.refinements : [];
2872
+ const invariants = Array.isArray(raw.invariants) ? raw.invariants : [];
2873
+ const termination = Array.isArray(raw.termination) ? raw.termination : [];
2874
+ const temporal = Array.isArray(raw.temporal) ? raw.temporal : [];
2875
+ const obligations = Array.isArray(raw.obligations) ? raw.obligations : [];
2876
+ const artifacts = Array.isArray(raw.artifacts) ? raw.artifacts : [];
2877
+ const assumptions = Array.isArray(raw.assumptions) ? raw.assumptions : [];
2878
+ const evidence = Array.isArray(raw.evidence) ? raw.evidence : [];
2879
+ const allContracts = [...contracts, ...refinements, ...invariants, ...termination, ...temporal];
2880
+ const byStatus = {};
2881
+ const byContractKind = {};
2882
+ const byArtifactKind = {};
2883
+ for (const obligation of obligations) {
2884
+ const status = String(obligation?.status ?? 'unknown');
2885
+ byStatus[status] = (byStatus[status] ?? 0) + 1;
2886
+ }
2887
+ for (const contract of allContracts) {
2888
+ const kind = String(contract?.kind ?? 'unknown');
2889
+ byContractKind[kind] = (byContractKind[kind] ?? 0) + 1;
2890
+ }
2891
+ for (const artifact of artifacts) {
2892
+ const kind = String(artifact?.kind ?? 'unknown');
2893
+ byArtifactKind[kind] = (byArtifactKind[kind] ?? 0) + 1;
2894
+ }
2895
+ const total = allContracts.length + obligations.length + artifacts.length + assumptions.length;
2896
+ return {
2897
+ total,
2898
+ ids: uniqueStrings([
2899
+ raw.id,
2900
+ ...allContracts.map((record) => record?.id),
2901
+ ...obligations.map((record) => record?.id),
2902
+ ...artifacts.map((record) => record?.id),
2903
+ ...assumptions.map((record) => record?.id),
2904
+ ...evidence.map((record) => record?.id)
2905
+ ].filter(Boolean).map(String)),
2906
+ contracts: contracts.length,
2907
+ refinements: refinements.length,
2908
+ invariants: invariants.length,
2909
+ termination: termination.length,
2910
+ temporal: temporal.length,
2911
+ obligations: obligations.length,
2912
+ artifacts: artifacts.length,
2913
+ assumptions: assumptions.length,
2914
+ evidence: evidence.length,
2915
+ discharged: byStatus.discharged ?? 0,
2916
+ failed: byStatus.failed ?? 0,
2917
+ open: byStatus.open ?? 0,
2918
+ unknown: byStatus.unknown ?? 0,
2919
+ stale: byStatus.stale ?? 0,
2920
+ assumed: byStatus.assumed ?? 0,
2921
+ contractKinds: uniqueStrings(Object.keys(byContractKind)),
2922
+ artifactKinds: uniqueStrings(Object.keys(byArtifactKind)),
2923
+ byStatus,
2924
+ byContractKind,
2925
+ byArtifactKind,
2926
+ empty: total === 0
2927
+ };
2928
+ }
2929
+ function hasProofSpecSummaryShape(value) {
2930
+ return typeof value.total === 'number' ||
2931
+ typeof value.obligations === 'number' ||
2932
+ typeof value.contracts === 'number' ||
2933
+ typeof value.failed === 'number';
2934
+ }
2935
+ function normalizeProofSpecSummary(value) {
2936
+ const summary = emptyProofSpecSummary();
2937
+ mergeProofSpecSummary(summary, value);
2938
+ summary.empty = summary.total === 0;
2939
+ return summary;
2940
+ }
2941
+ function emptyProofSpecSummary() {
2942
+ return {
2943
+ total: 0,
2944
+ ids: [],
2945
+ contracts: 0,
2946
+ refinements: 0,
2947
+ invariants: 0,
2948
+ termination: 0,
2949
+ temporal: 0,
2950
+ obligations: 0,
2951
+ artifacts: 0,
2952
+ assumptions: 0,
2953
+ evidence: 0,
2954
+ discharged: 0,
2955
+ failed: 0,
2956
+ open: 0,
2957
+ unknown: 0,
2958
+ stale: 0,
2959
+ assumed: 0,
2960
+ contractKinds: [],
2961
+ artifactKinds: [],
2962
+ byStatus: {},
2963
+ byContractKind: {},
2964
+ byArtifactKind: {},
2965
+ empty: true
2966
+ };
2967
+ }
2968
+ function mergeProofSpecSummary(target, input) {
2969
+ if (!input || typeof input !== 'object')
2970
+ return;
2971
+ for (const key of ['total', 'contracts', 'refinements', 'invariants', 'termination', 'temporal', 'obligations', 'artifacts', 'assumptions', 'evidence', 'discharged', 'failed', 'open', 'unknown', 'stale', 'assumed']) {
2972
+ target[key] += nonNegativeNumber(input[key]);
2973
+ }
2974
+ target.ids = uniqueStrings([...target.ids, ...proofStringList(input.ids)]);
2975
+ target.contractKinds = uniqueStrings([...target.contractKinds, ...proofStringList(input.contractKinds)]);
2976
+ target.artifactKinds = uniqueStrings([...target.artifactKinds, ...proofStringList(input.artifactKinds)]);
2977
+ for (const [status, count] of Object.entries(numberRecord(input.byStatus))) {
2978
+ target.byStatus[status] = (target.byStatus[status] ?? 0) + count;
2979
+ }
2980
+ for (const [kind, count] of Object.entries(numberRecord(input.byContractKind))) {
2981
+ target.byContractKind[kind] = (target.byContractKind[kind] ?? 0) + count;
2982
+ }
2983
+ for (const [kind, count] of Object.entries(numberRecord(input.byArtifactKind))) {
2984
+ target.byArtifactKind[kind] = (target.byArtifactKind[kind] ?? 0) + count;
2985
+ }
2986
+ }
2987
+ function proofStringList(value) {
2988
+ if (!Array.isArray(value))
2989
+ return [];
2990
+ return value.map((entry) => String(entry)).filter(Boolean);
2991
+ }
2992
+ function summarizeSemanticImportUniversalAstLayers(records) {
2993
+ const byName = {};
2994
+ const names = [];
2995
+ const ids = [];
2996
+ for (const record of records) {
2997
+ for (const name of record.universalAstLayers?.names ?? []) {
2998
+ names.push(name);
2999
+ byName[name] = (byName[name] ?? 0) + 1;
3000
+ }
3001
+ ids.push(...(record.universalAstLayers?.ids ?? []));
3002
+ }
3003
+ const uniqueNames = uniqueStrings(names);
3004
+ const uniqueIds = uniqueStrings(ids);
3005
+ return {
3006
+ total: records.reduce((sum, record) => sum + (record.universalAstLayers?.total ?? 0), 0),
3007
+ names: uniqueNames,
3008
+ ids: uniqueIds,
3009
+ byName,
3010
+ empty: uniqueIds.length === 0
3011
+ };
3012
+ }
3013
+ function summarizeUniversalAstLayers(universalAst, semanticSidecar) {
3014
+ const layers = collectUniversalAstLayerRecords(universalAst?.layers);
3015
+ const sidecarNames = Array.isArray(semanticSidecar?.summary?.universalAstLayerNames)
3016
+ ? semanticSidecar.summary.universalAstLayerNames
3017
+ : Array.isArray(semanticSidecar?.universalAstLayers?.names)
3018
+ ? semanticSidecar.universalAstLayers.names
3019
+ : [];
3020
+ const sidecarIds = Array.isArray(semanticSidecar?.universalAstLayers?.ids) ? semanticSidecar.universalAstLayers.ids : [];
3021
+ const byName = {};
3022
+ for (const layer of layers) {
3023
+ if (!layer?.layer)
3024
+ continue;
3025
+ byName[String(layer.layer)] = (byName[String(layer.layer)] ?? 0) + 1;
3026
+ }
3027
+ for (const [name, count] of Object.entries(semanticSidecar?.universalAstLayers?.byName ?? {})) {
3028
+ byName[name] = Math.max(byName[name] ?? 0, Number(count) || 0);
3029
+ }
3030
+ const names = uniqueStrings([
3031
+ ...layers.map((layer) => String(layer?.layer ?? '')).filter(Boolean),
3032
+ ...sidecarNames.map((name) => String(name)).filter(Boolean)
3033
+ ]);
3034
+ const ids = uniqueStrings([
3035
+ ...layers.map((layer) => String(layer?.id ?? '')).filter(Boolean),
3036
+ ...sidecarIds.map((id) => String(id)).filter(Boolean)
3037
+ ]);
3038
+ const total = Math.max(layers.length, Number(semanticSidecar?.universalAstLayers?.total ?? 0) || 0, ids.length);
3039
+ return { total, names, ids, byName, empty: total === 0 };
3040
+ }
3041
+ function collectUniversalAstLayerRecords(layers) {
3042
+ if (!layers)
3043
+ return [];
3044
+ if (Array.isArray(layers))
3045
+ return layers.filter(Boolean);
3046
+ if (typeof layers !== 'object')
3047
+ return [];
3048
+ return Object.values(layers).flatMap((value) => Array.isArray(value) ? value : [value]).filter(Boolean);
3049
+ }
2735
3050
  function summarizeNativeSourceProjection(value) {
2736
3051
  if (!value || typeof value !== 'object')
2737
3052
  return undefined;