chainlesschain 0.51.0 → 0.81.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (70) hide show
  1. package/package.json +1 -1
  2. package/src/assets/web-panel/.build-hash +1 -1
  3. package/src/assets/web-panel/assets/{AppLayout-Rvi759IS.js → AppLayout-6SPt_8Y_.js} +1 -1
  4. package/src/assets/web-panel/assets/{Dashboard-DBhFxXYQ.js → Dashboard-Br7kCwKJ.js} +2 -2
  5. package/src/assets/web-panel/assets/Dashboard-CKeMmCoT.css +1 -0
  6. package/src/assets/web-panel/assets/{index-uL0cZ8N_.js → index-tN-8TosE.js} +2 -2
  7. package/src/assets/web-panel/index.html +2 -2
  8. package/src/commands/a2a.js +380 -0
  9. package/src/commands/agent-network.js +785 -0
  10. package/src/commands/automation.js +654 -0
  11. package/src/commands/bi.js +348 -0
  12. package/src/commands/crosschain.js +218 -0
  13. package/src/commands/dao.js +565 -0
  14. package/src/commands/did-v2.js +620 -0
  15. package/src/commands/dlp.js +341 -0
  16. package/src/commands/economy.js +578 -0
  17. package/src/commands/evolution.js +391 -0
  18. package/src/commands/evomap.js +394 -0
  19. package/src/commands/federation.js +283 -0
  20. package/src/commands/hmemory.js +442 -0
  21. package/src/commands/inference.js +318 -0
  22. package/src/commands/lowcode.js +356 -0
  23. package/src/commands/marketplace.js +256 -0
  24. package/src/commands/perf.js +433 -0
  25. package/src/commands/pipeline.js +449 -0
  26. package/src/commands/plugin-ecosystem.js +517 -0
  27. package/src/commands/privacy.js +321 -0
  28. package/src/commands/reputation.js +261 -0
  29. package/src/commands/sandbox.js +401 -0
  30. package/src/commands/siem.js +246 -0
  31. package/src/commands/sla.js +259 -0
  32. package/src/commands/social.js +311 -0
  33. package/src/commands/sso.js +798 -0
  34. package/src/commands/stress.js +230 -0
  35. package/src/commands/terraform.js +245 -0
  36. package/src/commands/workflow.js +320 -0
  37. package/src/commands/zkp.js +562 -1
  38. package/src/index.js +21 -0
  39. package/src/lib/a2a-protocol.js +451 -0
  40. package/src/lib/agent-economy.js +479 -0
  41. package/src/lib/agent-network.js +1121 -0
  42. package/src/lib/app-builder.js +239 -0
  43. package/src/lib/automation-engine.js +948 -0
  44. package/src/lib/bi-engine.js +338 -0
  45. package/src/lib/cross-chain.js +345 -0
  46. package/src/lib/dao-governance.js +569 -0
  47. package/src/lib/did-v2-manager.js +1127 -0
  48. package/src/lib/dlp-engine.js +389 -0
  49. package/src/lib/evolution-system.js +453 -0
  50. package/src/lib/evomap-federation.js +177 -0
  51. package/src/lib/evomap-governance.js +276 -0
  52. package/src/lib/federation-hardening.js +259 -0
  53. package/src/lib/hierarchical-memory.js +481 -0
  54. package/src/lib/inference-network.js +330 -0
  55. package/src/lib/perf-tuning.js +734 -0
  56. package/src/lib/pipeline-orchestrator.js +928 -0
  57. package/src/lib/plugin-ecosystem.js +1109 -0
  58. package/src/lib/privacy-computing.js +427 -0
  59. package/src/lib/reputation-optimizer.js +299 -0
  60. package/src/lib/sandbox-v2.js +306 -0
  61. package/src/lib/siem-exporter.js +333 -0
  62. package/src/lib/skill-marketplace.js +325 -0
  63. package/src/lib/sla-manager.js +275 -0
  64. package/src/lib/social-graph-analytics.js +707 -0
  65. package/src/lib/sso-manager.js +841 -0
  66. package/src/lib/stress-tester.js +330 -0
  67. package/src/lib/terraform-manager.js +363 -0
  68. package/src/lib/workflow-engine.js +454 -1
  69. package/src/lib/zkp-engine.js +523 -20
  70. package/src/assets/web-panel/assets/Dashboard-BS-tzGNj.css +0 -1
@@ -506,3 +506,456 @@ export function _resetState() {
506
506
  growthLog.length = 0;
507
507
  diagnoses.length = 0;
508
508
  }
509
+
510
+ // ═════════════════════════════════════════════════════════════
511
+ // Phase 100 — Self-Evolving AI V2 (canonical surface)
512
+ // Strictly additive — pre-existing exports above remain unchanged.
513
+ // ═════════════════════════════════════════════════════════════
514
+
515
+ export const CAPABILITY_DIMENSION = Object.freeze({
516
+ REASONING: "reasoning",
517
+ KNOWLEDGE: "knowledge",
518
+ CREATIVITY: "creativity",
519
+ ACCURACY: "accuracy",
520
+ SPEED: "speed",
521
+ ADAPTABILITY: "adaptability",
522
+ });
523
+
524
+ export const DIAGNOSIS_SEVERITY = Object.freeze({
525
+ NORMAL: "normal",
526
+ WARNING: "warning",
527
+ CRITICAL: "critical",
528
+ FATAL: "fatal",
529
+ });
530
+
531
+ export const REPAIR_STRATEGY = Object.freeze({
532
+ PARAMETER_TUNE: "parameter_tune",
533
+ MODEL_ROLLBACK: "model_rollback",
534
+ CACHE_REBUILD: "cache_rebuild",
535
+ FULL_RESET: "full_reset",
536
+ });
537
+
538
+ export const GROWTH_MILESTONE = Object.freeze({
539
+ CAPABILITY_GAIN: "capability_gain",
540
+ KNOWLEDGE_EXPANSION: "knowledge_expansion",
541
+ SELF_REPAIR_SUCCESS: "self_repair_success",
542
+ PREDICTION_ACCURACY: "prediction_accuracy",
543
+ });
544
+
545
+ const TRAIN_STRATEGY = Object.freeze({
546
+ REPLAY: "replay",
547
+ ELASTIC_WEIGHT: "elastic-weight",
548
+ KNOWLEDGE_DISTILL: "knowledge-distill",
549
+ });
550
+
551
+ const _v2CapabilitiesByDim = new Map(); // dimension → { id, dimension, score, previousScore, trend, sampleCount, assessedAt, metadata }
552
+ const _v2TrainingLog = []; // { id, strategy, dataSize, lossBefore, lossAfter, knowledgeRetention, durationMs, status, createdAt }
553
+ const _v2DiagnosisById = new Map(); // diagnosisId → { id, scope, severity, anomaliesDetected, rootCause, repairSuggestion, repairStatus, repairedAt, createdAt }
554
+ const _v2Milestones = []; // { id, type, description, capabilityId?, details, timestamp }
555
+ const _v2Config = {
556
+ enabled: true,
557
+ assessmentDimensions: Object.values(CAPABILITY_DIMENSION),
558
+ assessmentIntervalMs: 3600000,
559
+ trainingStrategy: TRAIN_STRATEGY.ELASTIC_WEIGHT,
560
+ knowledgeRetentionThreshold: 0.85,
561
+ diagnosisEnabled: true,
562
+ diagnosisIntervalMs: 600000,
563
+ autoRepairEnabled: true,
564
+ autoRepairMaxRetries: 3,
565
+ predictionHorizonMs: 86400000,
566
+ growthLogRetentionDays: 365,
567
+ };
568
+
569
+ function _isValidEnumValue(enumObj, value) {
570
+ return Object.values(enumObj).includes(value);
571
+ }
572
+
573
+ export function assessCapabilityV2({ dimension, score, metadata = {} }) {
574
+ if (!_isValidEnumValue(CAPABILITY_DIMENSION, dimension)) {
575
+ throw new Error(`Invalid dimension: ${dimension}`);
576
+ }
577
+ if (!Number.isFinite(score) || score < 0 || score > 1) {
578
+ throw new Error("Score must be a finite number in [0, 1]");
579
+ }
580
+ const now = Date.now();
581
+ let entry = _v2CapabilitiesByDim.get(dimension);
582
+ const isFirstSample = !entry;
583
+ if (!entry) {
584
+ entry = {
585
+ id: crypto.randomUUID(),
586
+ dimension,
587
+ score: 0,
588
+ previousScore: 0,
589
+ trend: "stable",
590
+ sampleCount: 0,
591
+ assessedAt: now,
592
+ metadata: { ...metadata },
593
+ };
594
+ _v2CapabilitiesByDim.set(dimension, entry);
595
+ }
596
+ entry.previousScore = entry.score;
597
+ entry.score = score;
598
+ entry.sampleCount += 1;
599
+ entry.assessedAt = now;
600
+ entry.metadata = { ...entry.metadata, ...metadata };
601
+ if (isFirstSample) {
602
+ entry.trend = "stable";
603
+ } else {
604
+ const delta = entry.score - entry.previousScore;
605
+ if (delta > 0.01) entry.trend = "improving";
606
+ else if (delta < -0.01) entry.trend = "declining";
607
+ else entry.trend = "stable";
608
+
609
+ if (entry.trend === "improving" && delta >= 0.1) {
610
+ recordMilestone({
611
+ type: GROWTH_MILESTONE.CAPABILITY_GAIN,
612
+ description: `${dimension} capability gained ${delta.toFixed(3)}`,
613
+ capabilityId: entry.id,
614
+ details: { dimension, delta, newScore: score },
615
+ });
616
+ }
617
+ }
618
+ return { ...entry };
619
+ }
620
+
621
+ export function getCapabilityV2(dimension) {
622
+ const entry = _v2CapabilitiesByDim.get(dimension);
623
+ return entry ? { ...entry } : null;
624
+ }
625
+
626
+ export function listCapabilitiesV2() {
627
+ return [..._v2CapabilitiesByDim.values()]
628
+ .map((e) => ({ ...e }))
629
+ .sort((a, b) => a.dimension.localeCompare(b.dimension));
630
+ }
631
+
632
+ export function trainIncrementalV2({
633
+ strategy,
634
+ dataSize,
635
+ lossBefore,
636
+ lossAfter,
637
+ durationMs = 0,
638
+ }) {
639
+ if (!_isValidEnumValue(TRAIN_STRATEGY, strategy)) {
640
+ throw new Error(`Invalid training strategy: ${strategy}`);
641
+ }
642
+ if (!Number.isFinite(dataSize) || dataSize < 0) {
643
+ throw new Error("dataSize must be a finite non-negative number");
644
+ }
645
+ if (!Number.isFinite(lossBefore) || !Number.isFinite(lossAfter)) {
646
+ throw new Error("lossBefore and lossAfter must be finite numbers");
647
+ }
648
+ const denom = Math.max(Math.abs(lossBefore), 0.01);
649
+ const knowledgeRetention = Math.max(
650
+ 0,
651
+ Math.min(1, 1 - Math.abs(lossAfter - lossBefore) / denom),
652
+ );
653
+ const entry = {
654
+ id: crypto.randomUUID(),
655
+ strategy,
656
+ dataSize,
657
+ lossBefore,
658
+ lossAfter,
659
+ knowledgeRetention,
660
+ durationMs,
661
+ status:
662
+ knowledgeRetention >= _v2Config.knowledgeRetentionThreshold
663
+ ? "completed"
664
+ : "retention_low",
665
+ createdAt: Date.now(),
666
+ };
667
+ _v2TrainingLog.push(entry);
668
+ if (entry.status === "completed" && lossAfter < lossBefore) {
669
+ recordMilestone({
670
+ type: GROWTH_MILESTONE.KNOWLEDGE_EXPANSION,
671
+ description: `${strategy} training reduced loss ${lossBefore}→${lossAfter}`,
672
+ details: { strategy, dataSize, knowledgeRetention },
673
+ });
674
+ }
675
+ return { ...entry };
676
+ }
677
+
678
+ export function listTrainingLogV2({ strategy, limit } = {}) {
679
+ let list = [..._v2TrainingLog];
680
+ if (strategy) list = list.filter((e) => e.strategy === strategy);
681
+ list.sort((a, b) => b.createdAt - a.createdAt);
682
+ if (Number.isFinite(limit) && limit > 0) list = list.slice(0, limit);
683
+ return list;
684
+ }
685
+
686
+ export function selfDiagnoseV2({ scope = "system", depth = "shallow" } = {}) {
687
+ const anomalies = [];
688
+ let severity = DIAGNOSIS_SEVERITY.NORMAL;
689
+
690
+ // Capability-based anomalies (V2 store)
691
+ for (const [, cap] of _v2CapabilitiesByDim) {
692
+ if (cap.trend === "declining" && cap.previousScore - cap.score >= 0.2) {
693
+ anomalies.push({
694
+ type: "sharp_capability_drop",
695
+ dimension: cap.dimension,
696
+ delta: cap.score - cap.previousScore,
697
+ });
698
+ if (severity === DIAGNOSIS_SEVERITY.NORMAL) {
699
+ severity = DIAGNOSIS_SEVERITY.WARNING;
700
+ }
701
+ }
702
+ }
703
+
704
+ // Training retention anomalies
705
+ const recentTrain = _v2TrainingLog.slice(-10);
706
+ const lowRetention = recentTrain.filter(
707
+ (t) => t.knowledgeRetention < _v2Config.knowledgeRetentionThreshold,
708
+ );
709
+ if (lowRetention.length >= 3) {
710
+ anomalies.push({
711
+ type: "catastrophic_forgetting",
712
+ count: lowRetention.length,
713
+ });
714
+ severity = DIAGNOSIS_SEVERITY.CRITICAL;
715
+ }
716
+
717
+ let rootCause = null;
718
+ let repairSuggestion = null;
719
+ if (anomalies.length > 0) {
720
+ const top = anomalies[0];
721
+ if (top.type === "sharp_capability_drop") {
722
+ rootCause = `Capability ${top.dimension} dropped sharply`;
723
+ repairSuggestion = REPAIR_STRATEGY.PARAMETER_TUNE;
724
+ } else if (top.type === "catastrophic_forgetting") {
725
+ rootCause = "Knowledge retention below threshold in recent training";
726
+ repairSuggestion = REPAIR_STRATEGY.MODEL_ROLLBACK;
727
+ }
728
+ }
729
+
730
+ const entry = {
731
+ id: crypto.randomUUID(),
732
+ scope,
733
+ depth,
734
+ severity,
735
+ anomaliesDetected: anomalies.length,
736
+ anomalies,
737
+ rootCause,
738
+ repairSuggestion,
739
+ repairStatus: "pending",
740
+ repairedAt: null,
741
+ createdAt: Date.now(),
742
+ };
743
+ _v2DiagnosisById.set(entry.id, entry);
744
+ return { ...entry };
745
+ }
746
+
747
+ export function getDiagnosisV2(diagnosisId) {
748
+ const entry = _v2DiagnosisById.get(diagnosisId);
749
+ return entry ? { ...entry } : null;
750
+ }
751
+
752
+ export function listDiagnosesV2({ severity } = {}) {
753
+ let list = [..._v2DiagnosisById.values()];
754
+ if (severity) list = list.filter((e) => e.severity === severity);
755
+ list.sort((a, b) => b.createdAt - a.createdAt);
756
+ return list.map((e) => ({ ...e }));
757
+ }
758
+
759
+ export function selfRepairV2({ diagnosisId, strategy }) {
760
+ if (!_isValidEnumValue(REPAIR_STRATEGY, strategy)) {
761
+ throw new Error(`Invalid repair strategy: ${strategy}`);
762
+ }
763
+ const entry = _v2DiagnosisById.get(diagnosisId);
764
+ if (!entry) throw new Error(`Diagnosis not found: ${diagnosisId}`);
765
+ if (entry.repairStatus === "completed") {
766
+ throw new Error("Diagnosis already repaired");
767
+ }
768
+
769
+ const actions = [];
770
+ switch (strategy) {
771
+ case REPAIR_STRATEGY.PARAMETER_TUNE:
772
+ actions.push("Adjusted adaptive hyperparameters");
773
+ break;
774
+ case REPAIR_STRATEGY.MODEL_ROLLBACK:
775
+ actions.push("Rolled back to last stable model checkpoint");
776
+ break;
777
+ case REPAIR_STRATEGY.CACHE_REBUILD:
778
+ actions.push("Invalidated inference caches; rebuild queued");
779
+ break;
780
+ case REPAIR_STRATEGY.FULL_RESET:
781
+ actions.push("Full reset scheduled — requires operator confirmation");
782
+ break;
783
+ }
784
+
785
+ entry.repairStatus = "completed";
786
+ entry.repairedAt = Date.now();
787
+ entry.repairStrategy = strategy;
788
+ entry.repairActions = actions;
789
+ _v2DiagnosisById.set(entry.id, entry);
790
+
791
+ recordMilestone({
792
+ type: GROWTH_MILESTONE.SELF_REPAIR_SUCCESS,
793
+ description: `Repaired diagnosis ${diagnosisId} via ${strategy}`,
794
+ details: { diagnosisId, strategy, actions },
795
+ });
796
+
797
+ return {
798
+ diagnosisId,
799
+ strategy,
800
+ actions,
801
+ repairedAt: entry.repairedAt,
802
+ };
803
+ }
804
+
805
+ export function predictBehaviorV2({ timeHorizonMs, context = {} } = {}) {
806
+ const horizon = Number.isFinite(timeHorizonMs)
807
+ ? timeHorizonMs
808
+ : _v2Config.predictionHorizonMs;
809
+ const recentMilestones = _v2Milestones.slice(-50);
810
+ const typeCounts = {};
811
+ for (const m of recentMilestones) {
812
+ typeCounts[m.type] = (typeCounts[m.type] || 0) + 1;
813
+ }
814
+ const total = recentMilestones.length || 1;
815
+ const predictions = Object.entries(typeCounts)
816
+ .map(([type, count]) => ({
817
+ type,
818
+ probability: parseFloat((count / total).toFixed(3)),
819
+ }))
820
+ .sort((a, b) => b.probability - a.probability);
821
+
822
+ const confidence = Math.min(0.95, 0.3 + recentMilestones.length * 0.015);
823
+ return {
824
+ horizonMs: horizon,
825
+ context,
826
+ predictions,
827
+ confidence: parseFloat(confidence.toFixed(3)),
828
+ basedOnMilestones: recentMilestones.length,
829
+ };
830
+ }
831
+
832
+ export function recordMilestone({
833
+ type,
834
+ description,
835
+ capabilityId = null,
836
+ details = {},
837
+ }) {
838
+ if (!_isValidEnumValue(GROWTH_MILESTONE, type)) {
839
+ throw new Error(`Invalid milestone type: ${type}`);
840
+ }
841
+ const entry = {
842
+ id: crypto.randomUUID(),
843
+ type,
844
+ description: String(description || ""),
845
+ capabilityId,
846
+ details,
847
+ timestamp: Date.now(),
848
+ };
849
+ _v2Milestones.push(entry);
850
+ return { ...entry };
851
+ }
852
+
853
+ export function getGrowthLogV2({
854
+ period,
855
+ milestoneOnly = false,
856
+ milestoneType,
857
+ limit,
858
+ } = {}) {
859
+ let list = [..._v2Milestones];
860
+ if (milestoneType) {
861
+ list = list.filter((m) => m.type === milestoneType);
862
+ } else if (milestoneOnly) {
863
+ // All entries in _v2Milestones are milestones by definition — keep for symmetry.
864
+ }
865
+ if (period && Number.isFinite(period.fromMs)) {
866
+ list = list.filter((m) => m.timestamp >= period.fromMs);
867
+ }
868
+ if (period && Number.isFinite(period.toMs)) {
869
+ list = list.filter((m) => m.timestamp <= period.toMs);
870
+ }
871
+ list.sort((a, b) => b.timestamp - a.timestamp);
872
+ if (Number.isFinite(limit) && limit > 0) list = list.slice(0, limit);
873
+ return list.map((e) => ({ ...e }));
874
+ }
875
+
876
+ const CONFIG_KEYS = Object.freeze([
877
+ "enabled",
878
+ "assessmentIntervalMs",
879
+ "trainingStrategy",
880
+ "knowledgeRetentionThreshold",
881
+ "diagnosisEnabled",
882
+ "diagnosisIntervalMs",
883
+ "autoRepairEnabled",
884
+ "autoRepairMaxRetries",
885
+ "predictionHorizonMs",
886
+ "growthLogRetentionDays",
887
+ ]);
888
+
889
+ export function configureEvolution({ key, value }) {
890
+ if (!CONFIG_KEYS.includes(key)) {
891
+ throw new Error(`Unknown config key: ${key}`);
892
+ }
893
+ if (key === "trainingStrategy") {
894
+ if (!_isValidEnumValue(TRAIN_STRATEGY, value)) {
895
+ throw new Error(`Invalid trainingStrategy: ${value}`);
896
+ }
897
+ } else if (key === "knowledgeRetentionThreshold") {
898
+ if (!Number.isFinite(value) || value < 0 || value > 1) {
899
+ throw new Error("knowledgeRetentionThreshold must be in [0, 1]");
900
+ }
901
+ } else if (
902
+ key === "assessmentIntervalMs" ||
903
+ key === "diagnosisIntervalMs" ||
904
+ key === "predictionHorizonMs"
905
+ ) {
906
+ if (!Number.isFinite(value) || value <= 0) {
907
+ throw new Error(`${key} must be a positive finite number`);
908
+ }
909
+ } else if (
910
+ key === "autoRepairMaxRetries" ||
911
+ key === "growthLogRetentionDays"
912
+ ) {
913
+ if (!Number.isInteger(value) || value < 0) {
914
+ throw new Error(`${key} must be a non-negative integer`);
915
+ }
916
+ }
917
+ _v2Config[key] = value;
918
+ return { ...getEvolutionConfig() };
919
+ }
920
+
921
+ export function getEvolutionConfig() {
922
+ return {
923
+ ..._v2Config,
924
+ assessmentDimensions: [..._v2Config.assessmentDimensions],
925
+ };
926
+ }
927
+
928
+ export function getEvolutionStatsV2() {
929
+ const bySeverity = {};
930
+ for (const [, d] of _v2DiagnosisById) {
931
+ bySeverity[d.severity] = (bySeverity[d.severity] || 0) + 1;
932
+ }
933
+ const byMilestone = {};
934
+ for (const m of _v2Milestones) {
935
+ byMilestone[m.type] = (byMilestone[m.type] || 0) + 1;
936
+ }
937
+ return {
938
+ capabilityCount: _v2CapabilitiesByDim.size,
939
+ trainingRuns: _v2TrainingLog.length,
940
+ diagnoses: { total: _v2DiagnosisById.size, bySeverity },
941
+ milestones: { total: _v2Milestones.length, byType: byMilestone },
942
+ };
943
+ }
944
+
945
+ export function _resetV2State() {
946
+ _v2CapabilitiesByDim.clear();
947
+ _v2TrainingLog.length = 0;
948
+ _v2DiagnosisById.clear();
949
+ _v2Milestones.length = 0;
950
+ _v2Config.enabled = true;
951
+ _v2Config.assessmentDimensions = Object.values(CAPABILITY_DIMENSION);
952
+ _v2Config.assessmentIntervalMs = 3600000;
953
+ _v2Config.trainingStrategy = TRAIN_STRATEGY.ELASTIC_WEIGHT;
954
+ _v2Config.knowledgeRetentionThreshold = 0.85;
955
+ _v2Config.diagnosisEnabled = true;
956
+ _v2Config.diagnosisIntervalMs = 600000;
957
+ _v2Config.autoRepairEnabled = true;
958
+ _v2Config.autoRepairMaxRetries = 3;
959
+ _v2Config.predictionHorizonMs = 86400000;
960
+ _v2Config.growthLogRetentionDays = 365;
961
+ }
@@ -238,3 +238,180 @@ export function _resetState() {
238
238
  _hubs.clear();
239
239
  _lineage.clear();
240
240
  }
241
+
242
+ /* ═══════════════════════════════════════════════════════════════
243
+ * V2 Canonical Surface (Phase 42 — EvoMap Advanced Federation)
244
+ * Strictly additive; legacy exports above remain unchanged.
245
+ * ═══════════════════════════════════════════════════════════════ */
246
+
247
+ export const HUB_STATUS_V2 = Object.freeze({
248
+ ONLINE: "online",
249
+ OFFLINE: "offline",
250
+ SYNCING: "syncing",
251
+ DEGRADED: "degraded",
252
+ });
253
+
254
+ export const TRUST_TIER = Object.freeze({
255
+ LOW: "low",
256
+ MEDIUM: "medium",
257
+ HIGH: "high",
258
+ });
259
+
260
+ export const MUTATION_TYPE = Object.freeze({
261
+ MUTATION: "mutation",
262
+ RECOMBINATION: "recombination",
263
+ CROSSOVER: "crossover",
264
+ DRIFT: "drift",
265
+ });
266
+
267
+ const _allowedHubTransitions = new Map([
268
+ [
269
+ HUB_STATUS_V2.ONLINE,
270
+ new Set([
271
+ HUB_STATUS_V2.OFFLINE,
272
+ HUB_STATUS_V2.SYNCING,
273
+ HUB_STATUS_V2.DEGRADED,
274
+ ]),
275
+ ],
276
+ [
277
+ HUB_STATUS_V2.OFFLINE,
278
+ new Set([HUB_STATUS_V2.SYNCING, HUB_STATUS_V2.ONLINE]),
279
+ ],
280
+ [
281
+ HUB_STATUS_V2.SYNCING,
282
+ new Set([
283
+ HUB_STATUS_V2.ONLINE,
284
+ HUB_STATUS_V2.DEGRADED,
285
+ HUB_STATUS_V2.OFFLINE,
286
+ ]),
287
+ ],
288
+ [
289
+ HUB_STATUS_V2.DEGRADED,
290
+ new Set([HUB_STATUS_V2.ONLINE, HUB_STATUS_V2.OFFLINE]),
291
+ ],
292
+ ]);
293
+
294
+ export function trustTier(score) {
295
+ if (typeof score !== "number" || Number.isNaN(score)) {
296
+ throw new Error("Trust score must be a number");
297
+ }
298
+ if (score < 0.3) return TRUST_TIER.LOW;
299
+ if (score < 0.7) return TRUST_TIER.MEDIUM;
300
+ return TRUST_TIER.HIGH;
301
+ }
302
+
303
+ export function setHubStatus(db, hubId, newStatus) {
304
+ const hub = _hubs.get(hubId);
305
+ if (!hub) throw new Error(`Hub not found: ${hubId}`);
306
+
307
+ const validStatuses = Object.values(HUB_STATUS_V2);
308
+ if (!validStatuses.includes(newStatus)) {
309
+ throw new Error(`Unknown hub status: ${newStatus}`);
310
+ }
311
+
312
+ const allowed = _allowedHubTransitions.get(hub.status);
313
+ if (!allowed || !allowed.has(newStatus)) {
314
+ throw new Error(
315
+ `Invalid hub status transition: ${hub.status} → ${newStatus}`,
316
+ );
317
+ }
318
+
319
+ hub.status = newStatus;
320
+
321
+ db.prepare(`UPDATE evomap_hub_federation SET status = ? WHERE id = ?`).run(
322
+ newStatus,
323
+ hubId,
324
+ );
325
+
326
+ return { hubId, status: newStatus };
327
+ }
328
+
329
+ export function listHubsV2(db, filter = {}) {
330
+ let hubs = [..._hubs.values()];
331
+
332
+ if (filter.status) {
333
+ hubs = hubs.filter((h) => h.status === filter.status);
334
+ }
335
+ if (filter.region) {
336
+ hubs = hubs.filter((h) => h.region === filter.region);
337
+ }
338
+ if (typeof filter.minTrust === "number") {
339
+ hubs = hubs.filter((h) => h.trustScore >= filter.minTrust);
340
+ }
341
+ if (filter.trustTier) {
342
+ hubs = hubs.filter((h) => trustTier(h.trustScore) === filter.trustTier);
343
+ }
344
+
345
+ const limit = filter.limit || 50;
346
+ return hubs.slice(0, limit).map((h) => ({
347
+ ...h,
348
+ trustTier: trustTier(h.trustScore),
349
+ }));
350
+ }
351
+
352
+ export function buildFederationContext() {
353
+ const hubs = [..._hubs.values()];
354
+ const lineageEntries = [..._lineage.values()];
355
+
356
+ const onlineHubs = hubs.filter(
357
+ (h) => h.status === HUB_STATUS_V2.ONLINE,
358
+ ).length;
359
+ const totalGenes = lineageEntries.length;
360
+ const avgFitness =
361
+ totalGenes === 0
362
+ ? 0
363
+ : lineageEntries.reduce((s, e) => s + e.fitnessScore, 0) / totalGenes;
364
+ const avgTrust =
365
+ hubs.length === 0
366
+ ? 0
367
+ : hubs.reduce((s, h) => s + h.trustScore, 0) / hubs.length;
368
+
369
+ return {
370
+ hubCount: hubs.length,
371
+ onlineHubs,
372
+ totalGenes,
373
+ avgFitness,
374
+ avgTrust,
375
+ avgTrustTier: hubs.length === 0 ? null : trustTier(avgTrust),
376
+ regions: [...new Set(hubs.map((h) => h.region))],
377
+ };
378
+ }
379
+
380
+ export function getFederationStatsV2() {
381
+ const hubs = [..._hubs.values()];
382
+ const lineageEntries = [..._lineage.values()];
383
+
384
+ const byStatus = {};
385
+ for (const status of Object.values(HUB_STATUS_V2)) {
386
+ byStatus[status] = hubs.filter((h) => h.status === status).length;
387
+ }
388
+
389
+ const byRegion = {};
390
+ for (const h of hubs) {
391
+ byRegion[h.region] = (byRegion[h.region] || 0) + 1;
392
+ }
393
+
394
+ const byTrustTier = {
395
+ [TRUST_TIER.LOW]: 0,
396
+ [TRUST_TIER.MEDIUM]: 0,
397
+ [TRUST_TIER.HIGH]: 0,
398
+ };
399
+ for (const h of hubs) {
400
+ byTrustTier[trustTier(h.trustScore)]++;
401
+ }
402
+
403
+ const byMutationType = {};
404
+ for (const e of lineageEntries) {
405
+ const type = e.mutationType || "unknown";
406
+ byMutationType[type] = (byMutationType[type] || 0) + 1;
407
+ }
408
+
409
+ return {
410
+ totalHubs: hubs.length,
411
+ totalGenes: lineageEntries.length,
412
+ byStatus,
413
+ byRegion,
414
+ byTrustTier,
415
+ byMutationType,
416
+ };
417
+ }