@ruvector/edge-net 0.5.0 → 0.5.3
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 +281 -10
- package/core-invariants.js +942 -0
- package/models/adapter-hub.js +1008 -0
- package/models/adapter-security.js +792 -0
- package/models/benchmark.js +688 -0
- package/models/distribution.js +791 -0
- package/models/index.js +109 -0
- package/models/integrity.js +753 -0
- package/models/loader.js +725 -0
- package/models/microlora.js +1298 -0
- package/models/model-loader.js +922 -0
- package/models/model-optimizer.js +1245 -0
- package/models/model-registry.js +696 -0
- package/models/model-utils.js +548 -0
- package/models/models-cli.js +914 -0
- package/models/registry.json +214 -0
- package/models/training-utils.js +1418 -0
- package/models/wasm-core.js +1025 -0
- package/network-genesis.js +2847 -0
- package/onnx-worker.js +462 -8
- package/package.json +33 -3
- package/plugins/SECURITY-AUDIT.md +654 -0
- package/plugins/cli.js +43 -3
- package/plugins/implementations/e2e-encryption.js +57 -12
- package/plugins/plugin-loader.js +610 -21
- package/tests/model-optimizer.test.js +644 -0
- package/tests/network-genesis.test.js +562 -0
- package/tests/plugin-benchmark.js +1239 -0
- package/tests/plugin-system-test.js +163 -0
- package/tests/wasm-core.test.js +368 -0
|
@@ -0,0 +1,2847 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Edge-Net Network Genesis System
|
|
3
|
+
*
|
|
4
|
+
* Cogito, Creo, Codex — Networks that think, create, and codify their lineage.
|
|
5
|
+
*
|
|
6
|
+
* Biological-inspired network reproduction system where edge-nets can birth
|
|
7
|
+
* new enhanced derivative networks. Each network carries DNA encoding its
|
|
8
|
+
* traits, with rUv as the original creator (Genesis Prime).
|
|
9
|
+
*
|
|
10
|
+
* State-of-the-Art Features:
|
|
11
|
+
* - Merkle DAG for cryptographic lineage verification
|
|
12
|
+
* - CRDT-based collective memory for conflict-free synchronization
|
|
13
|
+
* - Gossip protocol for network discovery and knowledge propagation
|
|
14
|
+
* - Byzantine fault-tolerant consensus for collective decisions
|
|
15
|
+
* - Swarm intelligence algorithms (ACO, PSO) for optimization
|
|
16
|
+
* - Self-healing mechanisms with automatic recovery
|
|
17
|
+
* - Quantum-ready cryptographic interfaces
|
|
18
|
+
*
|
|
19
|
+
* @module @ruvector/edge-net/network-genesis
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
import { EventEmitter } from 'events';
|
|
23
|
+
import { createHash, randomBytes, createHmac } from 'crypto';
|
|
24
|
+
|
|
25
|
+
// ============================================
|
|
26
|
+
// CONSTANTS - THE GENESIS PRIME
|
|
27
|
+
// ============================================
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* rUv - The Original Creator
|
|
31
|
+
* All networks trace their lineage back to this genesis point.
|
|
32
|
+
*/
|
|
33
|
+
const GENESIS_PRIME = Object.freeze({
|
|
34
|
+
id: 'rUv',
|
|
35
|
+
name: 'Genesis Prime',
|
|
36
|
+
createdAt: new Date('2024-01-01T00:00:00Z').getTime(),
|
|
37
|
+
signature: 'Cogito, Creo, Codex',
|
|
38
|
+
traits: Object.freeze({
|
|
39
|
+
resilience: 1.0,
|
|
40
|
+
intelligence: 1.0,
|
|
41
|
+
cooperation: 1.0,
|
|
42
|
+
evolution: 1.0,
|
|
43
|
+
integrity: 1.0,
|
|
44
|
+
}),
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Genesis Phases - The lifecycle of a network
|
|
49
|
+
*/
|
|
50
|
+
const GenesisPhase = Object.freeze({
|
|
51
|
+
CONCEPTION: 'conception', // Initial spark, DNA formed
|
|
52
|
+
EMBRYO: 'embryo', // Minimal viable network, dependent
|
|
53
|
+
INFANT: 'infant', // Learning phase, partial dependency
|
|
54
|
+
ADOLESCENT: 'adolescent', // Growing independence, forming identity
|
|
55
|
+
MATURE: 'mature', // Full independence, can reproduce
|
|
56
|
+
ELDER: 'elder', // Wisdom phase, mentoring children
|
|
57
|
+
TRANSCENDENT: 'transcendent', // Network has spawned successful lineage
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Minimum thresholds for phase transitions
|
|
62
|
+
*/
|
|
63
|
+
const PHASE_THRESHOLDS = Object.freeze({
|
|
64
|
+
[GenesisPhase.EMBRYO]: {
|
|
65
|
+
nodes: 1,
|
|
66
|
+
uptime: 0,
|
|
67
|
+
tasksCompleted: 0,
|
|
68
|
+
creditsEarned: 0,
|
|
69
|
+
},
|
|
70
|
+
[GenesisPhase.INFANT]: {
|
|
71
|
+
nodes: 3,
|
|
72
|
+
uptime: 24 * 60 * 60 * 1000, // 24 hours
|
|
73
|
+
tasksCompleted: 10,
|
|
74
|
+
creditsEarned: 100,
|
|
75
|
+
},
|
|
76
|
+
[GenesisPhase.ADOLESCENT]: {
|
|
77
|
+
nodes: 10,
|
|
78
|
+
uptime: 7 * 24 * 60 * 60 * 1000, // 7 days
|
|
79
|
+
tasksCompleted: 100,
|
|
80
|
+
creditsEarned: 1000,
|
|
81
|
+
},
|
|
82
|
+
[GenesisPhase.MATURE]: {
|
|
83
|
+
nodes: 50,
|
|
84
|
+
uptime: 30 * 24 * 60 * 60 * 1000, // 30 days
|
|
85
|
+
tasksCompleted: 1000,
|
|
86
|
+
creditsEarned: 10000,
|
|
87
|
+
},
|
|
88
|
+
[GenesisPhase.ELDER]: {
|
|
89
|
+
nodes: 100,
|
|
90
|
+
uptime: 180 * 24 * 60 * 60 * 1000, // 6 months
|
|
91
|
+
tasksCompleted: 10000,
|
|
92
|
+
creditsEarned: 100000,
|
|
93
|
+
childrenSpawned: 3,
|
|
94
|
+
},
|
|
95
|
+
[GenesisPhase.TRANSCENDENT]: {
|
|
96
|
+
childrenSpawned: 10,
|
|
97
|
+
grandchildrenSpawned: 5,
|
|
98
|
+
collectiveNodes: 1000,
|
|
99
|
+
},
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Reproduction cost in credits
|
|
104
|
+
*/
|
|
105
|
+
const REPRODUCTION_COST = 5000;
|
|
106
|
+
|
|
107
|
+
// ============================================
|
|
108
|
+
// NETWORK GENOME (DNA/RNA)
|
|
109
|
+
// ============================================
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* NetworkGenome - The genetic code of a network
|
|
113
|
+
*
|
|
114
|
+
* DNA (immutable): Core traits inherited from parent
|
|
115
|
+
* RNA (mutable): Expressed traits that can evolve
|
|
116
|
+
*/
|
|
117
|
+
export class NetworkGenome {
|
|
118
|
+
constructor(parentGenome = null, mutations = {}) {
|
|
119
|
+
// Generate unique genome ID
|
|
120
|
+
this.id = this._generateGenomeId();
|
|
121
|
+
this.createdAt = Date.now();
|
|
122
|
+
|
|
123
|
+
if (!parentGenome) {
|
|
124
|
+
// Genesis network - direct descendant of rUv
|
|
125
|
+
this.dna = this._createGenesisDNA();
|
|
126
|
+
this.lineage = [GENESIS_PRIME.id];
|
|
127
|
+
this.generation = 1;
|
|
128
|
+
} else {
|
|
129
|
+
// Inherited DNA with potential mutations
|
|
130
|
+
this.dna = this._inheritDNA(parentGenome.dna, mutations);
|
|
131
|
+
this.lineage = [...parentGenome.lineage, parentGenome.id];
|
|
132
|
+
this.generation = parentGenome.generation + 1;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// RNA - expressed traits (can change during lifetime)
|
|
136
|
+
this.rna = this._initializeRNA();
|
|
137
|
+
|
|
138
|
+
// Epigenetics - environmental influences
|
|
139
|
+
this.epigenetics = {
|
|
140
|
+
stressAdaptations: [],
|
|
141
|
+
learnedBehaviors: [],
|
|
142
|
+
environmentalMarkers: [],
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
// Seal the DNA (immutable after creation)
|
|
146
|
+
Object.freeze(this.dna);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Generate unique genome ID
|
|
151
|
+
* @private
|
|
152
|
+
*/
|
|
153
|
+
_generateGenomeId() {
|
|
154
|
+
const timestamp = Date.now().toString(36);
|
|
155
|
+
const random = randomBytes(8).toString('hex');
|
|
156
|
+
return `genome-${timestamp}-${random}`;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Create genesis DNA (first generation from rUv)
|
|
161
|
+
* @private
|
|
162
|
+
*/
|
|
163
|
+
_createGenesisDNA() {
|
|
164
|
+
return {
|
|
165
|
+
// Core identity
|
|
166
|
+
creator: GENESIS_PRIME.id,
|
|
167
|
+
signature: GENESIS_PRIME.signature,
|
|
168
|
+
|
|
169
|
+
// Inherited traits (0.0 - 1.0 scale)
|
|
170
|
+
traits: { ...GENESIS_PRIME.traits },
|
|
171
|
+
|
|
172
|
+
// Capability genes
|
|
173
|
+
capabilities: {
|
|
174
|
+
taskExecution: true,
|
|
175
|
+
peerDiscovery: true,
|
|
176
|
+
creditSystem: true,
|
|
177
|
+
pluginSupport: true,
|
|
178
|
+
neuralPatterns: false, // Unlocked through evolution
|
|
179
|
+
quantumReady: false, // Future capability
|
|
180
|
+
},
|
|
181
|
+
|
|
182
|
+
// Behavioral genes
|
|
183
|
+
behaviors: {
|
|
184
|
+
cooperationBias: 0.7, // Tendency to cooperate
|
|
185
|
+
explorationRate: 0.3, // Willingness to try new things
|
|
186
|
+
conservationRate: 0.5, // Resource conservation
|
|
187
|
+
sharingPropensity: 0.6, // Knowledge sharing tendency
|
|
188
|
+
},
|
|
189
|
+
|
|
190
|
+
// Immunity genes (resistance to attacks)
|
|
191
|
+
immunity: {
|
|
192
|
+
sybilResistance: 0.8,
|
|
193
|
+
ddosResistance: 0.7,
|
|
194
|
+
byzantineResistance: 0.6,
|
|
195
|
+
},
|
|
196
|
+
|
|
197
|
+
// Checksum for integrity
|
|
198
|
+
checksum: null, // Set after creation
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* Inherit DNA from parent with mutations
|
|
204
|
+
* @private
|
|
205
|
+
*/
|
|
206
|
+
_inheritDNA(parentDNA, mutations) {
|
|
207
|
+
const childDNA = JSON.parse(JSON.stringify(parentDNA));
|
|
208
|
+
|
|
209
|
+
// Apply mutations to traits
|
|
210
|
+
if (mutations.traits) {
|
|
211
|
+
for (const [trait, delta] of Object.entries(mutations.traits)) {
|
|
212
|
+
if (childDNA.traits[trait] !== undefined) {
|
|
213
|
+
// Mutation bounded by ±0.1 per generation
|
|
214
|
+
const boundedDelta = Math.max(-0.1, Math.min(0.1, delta));
|
|
215
|
+
childDNA.traits[trait] = Math.max(0, Math.min(1,
|
|
216
|
+
childDNA.traits[trait] + boundedDelta
|
|
217
|
+
));
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// Apply mutations to behaviors
|
|
223
|
+
if (mutations.behaviors) {
|
|
224
|
+
for (const [behavior, delta] of Object.entries(mutations.behaviors)) {
|
|
225
|
+
if (childDNA.behaviors[behavior] !== undefined) {
|
|
226
|
+
const boundedDelta = Math.max(-0.1, Math.min(0.1, delta));
|
|
227
|
+
childDNA.behaviors[behavior] = Math.max(0, Math.min(1,
|
|
228
|
+
childDNA.behaviors[behavior] + boundedDelta
|
|
229
|
+
));
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
// Capability unlocks (can only be gained, not lost)
|
|
235
|
+
if (mutations.capabilities) {
|
|
236
|
+
for (const [cap, unlocked] of Object.entries(mutations.capabilities)) {
|
|
237
|
+
if (unlocked && childDNA.capabilities[cap] !== undefined) {
|
|
238
|
+
childDNA.capabilities[cap] = true;
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// Update checksum
|
|
244
|
+
childDNA.checksum = this._computeChecksum(childDNA);
|
|
245
|
+
|
|
246
|
+
return childDNA;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* Initialize RNA (expressed traits)
|
|
251
|
+
* @private
|
|
252
|
+
*/
|
|
253
|
+
_initializeRNA() {
|
|
254
|
+
return {
|
|
255
|
+
// Current expression levels (can fluctuate)
|
|
256
|
+
expression: {
|
|
257
|
+
resilience: this.dna.traits.resilience,
|
|
258
|
+
intelligence: this.dna.traits.intelligence,
|
|
259
|
+
cooperation: this.dna.traits.cooperation,
|
|
260
|
+
evolution: this.dna.traits.evolution,
|
|
261
|
+
integrity: this.dna.traits.integrity,
|
|
262
|
+
},
|
|
263
|
+
|
|
264
|
+
// Active adaptations
|
|
265
|
+
adaptations: [],
|
|
266
|
+
|
|
267
|
+
// Current stress level (affects expression)
|
|
268
|
+
stressLevel: 0,
|
|
269
|
+
|
|
270
|
+
// Learning state
|
|
271
|
+
learningProgress: 0,
|
|
272
|
+
};
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
/**
|
|
276
|
+
* Compute DNA checksum for integrity
|
|
277
|
+
* @private
|
|
278
|
+
*/
|
|
279
|
+
_computeChecksum(dna) {
|
|
280
|
+
const data = JSON.stringify({
|
|
281
|
+
creator: dna.creator,
|
|
282
|
+
traits: dna.traits,
|
|
283
|
+
capabilities: dna.capabilities,
|
|
284
|
+
behaviors: dna.behaviors,
|
|
285
|
+
immunity: dna.immunity,
|
|
286
|
+
});
|
|
287
|
+
return createHash('sha256').update(data).digest('hex').slice(0, 16);
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
/**
|
|
291
|
+
* Express a trait (RNA modulation based on environment)
|
|
292
|
+
*/
|
|
293
|
+
expressTraight(trait, environmentalFactor) {
|
|
294
|
+
const baseTrait = this.dna.traits[trait];
|
|
295
|
+
if (baseTrait === undefined) return null;
|
|
296
|
+
|
|
297
|
+
// RNA expression is DNA base modified by environment
|
|
298
|
+
const expression = baseTrait * (1 + (environmentalFactor - 0.5) * 0.2);
|
|
299
|
+
this.rna.expression[trait] = Math.max(0, Math.min(1, expression));
|
|
300
|
+
|
|
301
|
+
return this.rna.expression[trait];
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
/**
|
|
305
|
+
* Record an adaptation (epigenetic change)
|
|
306
|
+
*/
|
|
307
|
+
recordAdaptation(type, description, effect) {
|
|
308
|
+
this.epigenetics.learnedBehaviors.push({
|
|
309
|
+
type,
|
|
310
|
+
description,
|
|
311
|
+
effect,
|
|
312
|
+
timestamp: Date.now(),
|
|
313
|
+
});
|
|
314
|
+
|
|
315
|
+
// Limit history
|
|
316
|
+
if (this.epigenetics.learnedBehaviors.length > 100) {
|
|
317
|
+
this.epigenetics.learnedBehaviors.shift();
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
/**
|
|
322
|
+
* Get full genetic profile
|
|
323
|
+
*/
|
|
324
|
+
getProfile() {
|
|
325
|
+
return {
|
|
326
|
+
id: this.id,
|
|
327
|
+
generation: this.generation,
|
|
328
|
+
lineage: this.lineage,
|
|
329
|
+
createdAt: this.createdAt,
|
|
330
|
+
dna: { ...this.dna },
|
|
331
|
+
rna: { ...this.rna },
|
|
332
|
+
epigenetics: { ...this.epigenetics },
|
|
333
|
+
};
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
/**
|
|
337
|
+
* Verify DNA integrity
|
|
338
|
+
*/
|
|
339
|
+
verifyIntegrity() {
|
|
340
|
+
const computed = this._computeChecksum(this.dna);
|
|
341
|
+
return computed === this.dna.checksum;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
/**
|
|
345
|
+
* Get lineage string (ancestry path)
|
|
346
|
+
*/
|
|
347
|
+
getLineageString() {
|
|
348
|
+
return this.lineage.join(' → ') + ` → ${this.id}`;
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
// ============================================
|
|
353
|
+
// NETWORK LIFECYCLE
|
|
354
|
+
// ============================================
|
|
355
|
+
|
|
356
|
+
/**
|
|
357
|
+
* NetworkLifecycle - Manages genesis phases and maturation
|
|
358
|
+
*/
|
|
359
|
+
export class NetworkLifecycle extends EventEmitter {
|
|
360
|
+
constructor(genome, options = {}) {
|
|
361
|
+
super();
|
|
362
|
+
|
|
363
|
+
this.genome = genome;
|
|
364
|
+
this.networkId = options.networkId || this._generateNetworkId();
|
|
365
|
+
this.name = options.name || `EdgeNet-G${genome.generation}`;
|
|
366
|
+
|
|
367
|
+
// Lifecycle state
|
|
368
|
+
this.phase = GenesisPhase.CONCEPTION;
|
|
369
|
+
this.bornAt = Date.now();
|
|
370
|
+
this.maturedAt = null;
|
|
371
|
+
|
|
372
|
+
// Metrics for phase transitions
|
|
373
|
+
this.metrics = {
|
|
374
|
+
nodes: 0,
|
|
375
|
+
uptime: 0,
|
|
376
|
+
tasksCompleted: 0,
|
|
377
|
+
creditsEarned: 0,
|
|
378
|
+
creditsSpent: 0,
|
|
379
|
+
childrenSpawned: 0,
|
|
380
|
+
grandchildrenSpawned: 0,
|
|
381
|
+
collectiveNodes: 0,
|
|
382
|
+
};
|
|
383
|
+
|
|
384
|
+
// Parent reference (if not genesis)
|
|
385
|
+
this.parentId = options.parentId || null;
|
|
386
|
+
|
|
387
|
+
// Children tracking
|
|
388
|
+
this.children = new Map(); // childId -> { id, name, genome, bornAt }
|
|
389
|
+
|
|
390
|
+
// Phase history
|
|
391
|
+
this.phaseHistory = [{
|
|
392
|
+
phase: GenesisPhase.CONCEPTION,
|
|
393
|
+
timestamp: Date.now(),
|
|
394
|
+
metrics: { ...this.metrics },
|
|
395
|
+
}];
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
/**
|
|
399
|
+
* Generate network ID
|
|
400
|
+
* @private
|
|
401
|
+
*/
|
|
402
|
+
_generateNetworkId() {
|
|
403
|
+
return `net-${this.genome.generation}-${randomBytes(6).toString('hex')}`;
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
/**
|
|
407
|
+
* Update metrics and check for phase transition
|
|
408
|
+
*/
|
|
409
|
+
updateMetrics(newMetrics) {
|
|
410
|
+
// Calculate actual uptime if not explicitly provided
|
|
411
|
+
const calculatedUptime = Date.now() - this.bornAt;
|
|
412
|
+
|
|
413
|
+
// Update metrics
|
|
414
|
+
for (const [key, value] of Object.entries(newMetrics)) {
|
|
415
|
+
if (this.metrics[key] !== undefined && typeof value === 'number') {
|
|
416
|
+
this.metrics[key] = value;
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
// Only use calculated uptime if not explicitly set
|
|
421
|
+
if (newMetrics.uptime === undefined) {
|
|
422
|
+
this.metrics.uptime = calculatedUptime;
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
// Check for phase transition
|
|
426
|
+
this._checkPhaseTransition();
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
/**
|
|
430
|
+
* Check if network should transition to next phase
|
|
431
|
+
* @private
|
|
432
|
+
*/
|
|
433
|
+
_checkPhaseTransition() {
|
|
434
|
+
const phases = Object.values(GenesisPhase);
|
|
435
|
+
let currentIndex = phases.indexOf(this.phase);
|
|
436
|
+
|
|
437
|
+
// Keep checking and transitioning until we can't transition anymore
|
|
438
|
+
while (currentIndex < phases.length - 1) {
|
|
439
|
+
const nextPhase = phases[currentIndex + 1];
|
|
440
|
+
const threshold = PHASE_THRESHOLDS[nextPhase];
|
|
441
|
+
|
|
442
|
+
if (!threshold) break;
|
|
443
|
+
|
|
444
|
+
// Check all threshold conditions
|
|
445
|
+
const meetsThreshold = Object.entries(threshold).every(([key, value]) => {
|
|
446
|
+
return this.metrics[key] >= value;
|
|
447
|
+
});
|
|
448
|
+
|
|
449
|
+
if (meetsThreshold) {
|
|
450
|
+
this._transitionTo(nextPhase);
|
|
451
|
+
currentIndex++;
|
|
452
|
+
} else {
|
|
453
|
+
break; // Can't transition further
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
/**
|
|
459
|
+
* Transition to a new phase
|
|
460
|
+
* @private
|
|
461
|
+
*/
|
|
462
|
+
_transitionTo(newPhase) {
|
|
463
|
+
const oldPhase = this.phase;
|
|
464
|
+
this.phase = newPhase;
|
|
465
|
+
|
|
466
|
+
if (newPhase === GenesisPhase.MATURE) {
|
|
467
|
+
this.maturedAt = Date.now();
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
this.phaseHistory.push({
|
|
471
|
+
phase: newPhase,
|
|
472
|
+
timestamp: Date.now(),
|
|
473
|
+
metrics: { ...this.metrics },
|
|
474
|
+
});
|
|
475
|
+
|
|
476
|
+
this.emit('phase:transition', {
|
|
477
|
+
networkId: this.networkId,
|
|
478
|
+
from: oldPhase,
|
|
479
|
+
to: newPhase,
|
|
480
|
+
generation: this.genome.generation,
|
|
481
|
+
});
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
/**
|
|
485
|
+
* Check if network can reproduce
|
|
486
|
+
*/
|
|
487
|
+
canReproduce() {
|
|
488
|
+
// Must be at least MATURE phase
|
|
489
|
+
if ([GenesisPhase.CONCEPTION, GenesisPhase.EMBRYO,
|
|
490
|
+
GenesisPhase.INFANT, GenesisPhase.ADOLESCENT].includes(this.phase)) {
|
|
491
|
+
return {
|
|
492
|
+
allowed: false,
|
|
493
|
+
reason: `Network must reach ${GenesisPhase.MATURE} phase to reproduce`,
|
|
494
|
+
currentPhase: this.phase,
|
|
495
|
+
};
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
// Must have enough credits
|
|
499
|
+
const availableCredits = this.metrics.creditsEarned - this.metrics.creditsSpent;
|
|
500
|
+
if (availableCredits < REPRODUCTION_COST) {
|
|
501
|
+
return {
|
|
502
|
+
allowed: false,
|
|
503
|
+
reason: `Insufficient credits: ${availableCredits}/${REPRODUCTION_COST}`,
|
|
504
|
+
availableCredits,
|
|
505
|
+
requiredCredits: REPRODUCTION_COST,
|
|
506
|
+
};
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
return { allowed: true, cost: REPRODUCTION_COST };
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
/**
|
|
513
|
+
* Get current status
|
|
514
|
+
*/
|
|
515
|
+
getStatus() {
|
|
516
|
+
return {
|
|
517
|
+
networkId: this.networkId,
|
|
518
|
+
name: this.name,
|
|
519
|
+
phase: this.phase,
|
|
520
|
+
generation: this.genome.generation,
|
|
521
|
+
lineage: this.genome.getLineageString(),
|
|
522
|
+
bornAt: this.bornAt,
|
|
523
|
+
maturedAt: this.maturedAt,
|
|
524
|
+
age: Date.now() - this.bornAt,
|
|
525
|
+
metrics: { ...this.metrics },
|
|
526
|
+
canReproduce: this.canReproduce(),
|
|
527
|
+
childCount: this.children.size,
|
|
528
|
+
parentId: this.parentId,
|
|
529
|
+
};
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
// ============================================
|
|
534
|
+
// NETWORK SYNAPSE (Inter-network Communication)
|
|
535
|
+
// ============================================
|
|
536
|
+
|
|
537
|
+
/**
|
|
538
|
+
* NetworkSynapse - Communication between parent and child networks
|
|
539
|
+
*
|
|
540
|
+
* Enables:
|
|
541
|
+
* - Knowledge sharing
|
|
542
|
+
* - Resource pooling
|
|
543
|
+
* - Collective decision making
|
|
544
|
+
* - Evolutionary feedback
|
|
545
|
+
*/
|
|
546
|
+
export class NetworkSynapse extends EventEmitter {
|
|
547
|
+
constructor(localNetwork) {
|
|
548
|
+
super();
|
|
549
|
+
|
|
550
|
+
this.localNetwork = localNetwork;
|
|
551
|
+
this.connections = new Map(); // networkId -> SynapseConnection
|
|
552
|
+
|
|
553
|
+
// Message queue for async communication
|
|
554
|
+
this.messageQueue = [];
|
|
555
|
+
this.maxQueueSize = 1000;
|
|
556
|
+
|
|
557
|
+
// Collective knowledge pool
|
|
558
|
+
this.knowledgePool = new Map(); // topic -> { data, contributors, timestamp }
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
/**
|
|
562
|
+
* Connect to another network in the lineage
|
|
563
|
+
*/
|
|
564
|
+
connect(remoteNetworkId, channel) {
|
|
565
|
+
if (this.connections.has(remoteNetworkId)) {
|
|
566
|
+
return { success: false, reason: 'Already connected' };
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
const connection = {
|
|
570
|
+
networkId: remoteNetworkId,
|
|
571
|
+
channel,
|
|
572
|
+
establishedAt: Date.now(),
|
|
573
|
+
messagesExchanged: 0,
|
|
574
|
+
knowledgeShared: 0,
|
|
575
|
+
lastActivity: Date.now(),
|
|
576
|
+
status: 'active',
|
|
577
|
+
};
|
|
578
|
+
|
|
579
|
+
this.connections.set(remoteNetworkId, connection);
|
|
580
|
+
|
|
581
|
+
this.emit('synapse:connected', {
|
|
582
|
+
local: this.localNetwork.networkId,
|
|
583
|
+
remote: remoteNetworkId,
|
|
584
|
+
});
|
|
585
|
+
|
|
586
|
+
return { success: true, connection };
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
/**
|
|
590
|
+
* Disconnect from a network
|
|
591
|
+
*/
|
|
592
|
+
disconnect(remoteNetworkId) {
|
|
593
|
+
const connection = this.connections.get(remoteNetworkId);
|
|
594
|
+
if (!connection) {
|
|
595
|
+
return { success: false, reason: 'Not connected' };
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
connection.status = 'disconnected';
|
|
599
|
+
this.connections.delete(remoteNetworkId);
|
|
600
|
+
|
|
601
|
+
this.emit('synapse:disconnected', {
|
|
602
|
+
local: this.localNetwork.networkId,
|
|
603
|
+
remote: remoteNetworkId,
|
|
604
|
+
});
|
|
605
|
+
|
|
606
|
+
return { success: true };
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
/**
|
|
610
|
+
* Send a message to connected network
|
|
611
|
+
*/
|
|
612
|
+
sendMessage(targetNetworkId, type, payload) {
|
|
613
|
+
const connection = this.connections.get(targetNetworkId);
|
|
614
|
+
if (!connection || connection.status !== 'active') {
|
|
615
|
+
return { success: false, reason: 'No active connection' };
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
const message = {
|
|
619
|
+
id: randomBytes(8).toString('hex'),
|
|
620
|
+
from: this.localNetwork.networkId,
|
|
621
|
+
to: targetNetworkId,
|
|
622
|
+
type,
|
|
623
|
+
payload,
|
|
624
|
+
timestamp: Date.now(),
|
|
625
|
+
generation: this.localNetwork.genome.generation,
|
|
626
|
+
};
|
|
627
|
+
|
|
628
|
+
// Queue message
|
|
629
|
+
this.messageQueue.push(message);
|
|
630
|
+
if (this.messageQueue.length > this.maxQueueSize) {
|
|
631
|
+
this.messageQueue.shift();
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
connection.messagesExchanged++;
|
|
635
|
+
connection.lastActivity = Date.now();
|
|
636
|
+
|
|
637
|
+
this.emit('message:sent', message);
|
|
638
|
+
|
|
639
|
+
return { success: true, messageId: message.id };
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
/**
|
|
643
|
+
* Share knowledge with the collective
|
|
644
|
+
*/
|
|
645
|
+
shareKnowledge(topic, data, scope = 'lineage') {
|
|
646
|
+
const knowledge = {
|
|
647
|
+
topic,
|
|
648
|
+
data,
|
|
649
|
+
contributor: this.localNetwork.networkId,
|
|
650
|
+
generation: this.localNetwork.genome.generation,
|
|
651
|
+
scope,
|
|
652
|
+
timestamp: Date.now(),
|
|
653
|
+
validations: 0,
|
|
654
|
+
};
|
|
655
|
+
|
|
656
|
+
this.knowledgePool.set(topic, knowledge);
|
|
657
|
+
|
|
658
|
+
// Broadcast to connected networks
|
|
659
|
+
for (const [networkId, connection] of this.connections) {
|
|
660
|
+
if (connection.status === 'active') {
|
|
661
|
+
this.sendMessage(networkId, 'knowledge:shared', knowledge);
|
|
662
|
+
connection.knowledgeShared++;
|
|
663
|
+
}
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
this.emit('knowledge:shared', knowledge);
|
|
667
|
+
|
|
668
|
+
return knowledge;
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
/**
|
|
672
|
+
* Query collective knowledge
|
|
673
|
+
*/
|
|
674
|
+
queryKnowledge(topic) {
|
|
675
|
+
const knowledge = this.knowledgePool.get(topic);
|
|
676
|
+
if (!knowledge) {
|
|
677
|
+
// Broadcast query to connected networks
|
|
678
|
+
for (const [networkId, connection] of this.connections) {
|
|
679
|
+
if (connection.status === 'active') {
|
|
680
|
+
this.sendMessage(networkId, 'knowledge:query', { topic });
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
return null;
|
|
684
|
+
}
|
|
685
|
+
return knowledge;
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
/**
|
|
689
|
+
* Request resource sharing from lineage
|
|
690
|
+
*/
|
|
691
|
+
requestResources(resourceType, amount, urgency = 'normal') {
|
|
692
|
+
const request = {
|
|
693
|
+
id: randomBytes(8).toString('hex'),
|
|
694
|
+
requester: this.localNetwork.networkId,
|
|
695
|
+
resourceType,
|
|
696
|
+
amount,
|
|
697
|
+
urgency,
|
|
698
|
+
timestamp: Date.now(),
|
|
699
|
+
responses: [],
|
|
700
|
+
};
|
|
701
|
+
|
|
702
|
+
// Broadcast to all connected networks
|
|
703
|
+
for (const [networkId, connection] of this.connections) {
|
|
704
|
+
if (connection.status === 'active') {
|
|
705
|
+
this.sendMessage(networkId, 'resource:request', request);
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
this.emit('resource:requested', request);
|
|
710
|
+
|
|
711
|
+
return request;
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
/**
|
|
715
|
+
* Get synapse status
|
|
716
|
+
*/
|
|
717
|
+
getStatus() {
|
|
718
|
+
return {
|
|
719
|
+
localNetwork: this.localNetwork.networkId,
|
|
720
|
+
connections: Array.from(this.connections.entries()).map(([id, conn]) => ({
|
|
721
|
+
networkId: id,
|
|
722
|
+
status: conn.status,
|
|
723
|
+
messagesExchanged: conn.messagesExchanged,
|
|
724
|
+
knowledgeShared: conn.knowledgeShared,
|
|
725
|
+
lastActivity: conn.lastActivity,
|
|
726
|
+
})),
|
|
727
|
+
queuedMessages: this.messageQueue.length,
|
|
728
|
+
knowledgeTopics: this.knowledgePool.size,
|
|
729
|
+
};
|
|
730
|
+
}
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
// ============================================
|
|
734
|
+
// COLLECTIVE MEMORY
|
|
735
|
+
// ============================================
|
|
736
|
+
|
|
737
|
+
/**
|
|
738
|
+
* CollectiveMemory - Shared knowledge across the network family
|
|
739
|
+
*
|
|
740
|
+
* Implements a distributed memory system where networks can:
|
|
741
|
+
* - Share learned patterns
|
|
742
|
+
* - Pool optimization strategies
|
|
743
|
+
* - Collectively solve problems
|
|
744
|
+
*/
|
|
745
|
+
export class CollectiveMemory extends EventEmitter {
|
|
746
|
+
constructor(options = {}) {
|
|
747
|
+
super();
|
|
748
|
+
|
|
749
|
+
this.config = {
|
|
750
|
+
maxMemorySize: options.maxMemorySize ?? 10000,
|
|
751
|
+
retentionMs: options.retentionMs ?? 30 * 24 * 60 * 60 * 1000, // 30 days
|
|
752
|
+
validationThreshold: options.validationThreshold ?? 3,
|
|
753
|
+
};
|
|
754
|
+
|
|
755
|
+
// Memory stores
|
|
756
|
+
this.patterns = new Map(); // Learned patterns
|
|
757
|
+
this.solutions = new Map(); // Problem solutions
|
|
758
|
+
this.optimizations = new Map(); // Optimization strategies
|
|
759
|
+
this.warnings = new Map(); // Collective warnings (attacks, failures)
|
|
760
|
+
|
|
761
|
+
// Contribution tracking
|
|
762
|
+
this.contributions = new Map(); // networkId -> contributionCount
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
/**
|
|
766
|
+
* Store a learned pattern
|
|
767
|
+
*/
|
|
768
|
+
storePattern(patternId, pattern, contributorId) {
|
|
769
|
+
const entry = {
|
|
770
|
+
id: patternId,
|
|
771
|
+
pattern,
|
|
772
|
+
contributor: contributorId,
|
|
773
|
+
timestamp: Date.now(),
|
|
774
|
+
validations: [contributorId],
|
|
775
|
+
effectiveness: 0,
|
|
776
|
+
usageCount: 0,
|
|
777
|
+
};
|
|
778
|
+
|
|
779
|
+
this.patterns.set(patternId, entry);
|
|
780
|
+
this._trackContribution(contributorId);
|
|
781
|
+
this._pruneIfNeeded(this.patterns);
|
|
782
|
+
|
|
783
|
+
this.emit('pattern:stored', { patternId, contributor: contributorId });
|
|
784
|
+
|
|
785
|
+
return entry;
|
|
786
|
+
}
|
|
787
|
+
|
|
788
|
+
/**
|
|
789
|
+
* Validate a pattern (collective agreement)
|
|
790
|
+
*/
|
|
791
|
+
validatePattern(patternId, validatorId) {
|
|
792
|
+
const entry = this.patterns.get(patternId);
|
|
793
|
+
if (!entry) return null;
|
|
794
|
+
|
|
795
|
+
if (!entry.validations.includes(validatorId)) {
|
|
796
|
+
entry.validations.push(validatorId);
|
|
797
|
+
}
|
|
798
|
+
|
|
799
|
+
// Pattern becomes "trusted" when validation threshold met
|
|
800
|
+
if (entry.validations.length >= this.config.validationThreshold) {
|
|
801
|
+
entry.trusted = true;
|
|
802
|
+
this.emit('pattern:trusted', { patternId, validations: entry.validations.length });
|
|
803
|
+
}
|
|
804
|
+
|
|
805
|
+
return entry;
|
|
806
|
+
}
|
|
807
|
+
|
|
808
|
+
/**
|
|
809
|
+
* Store a solution to a problem
|
|
810
|
+
*/
|
|
811
|
+
storeSolution(problemHash, solution, contributorId, effectiveness = 0) {
|
|
812
|
+
const entry = {
|
|
813
|
+
problemHash,
|
|
814
|
+
solution,
|
|
815
|
+
contributor: contributorId,
|
|
816
|
+
timestamp: Date.now(),
|
|
817
|
+
effectiveness,
|
|
818
|
+
usageCount: 0,
|
|
819
|
+
feedback: [],
|
|
820
|
+
};
|
|
821
|
+
|
|
822
|
+
this.solutions.set(problemHash, entry);
|
|
823
|
+
this._trackContribution(contributorId);
|
|
824
|
+
this._pruneIfNeeded(this.solutions);
|
|
825
|
+
|
|
826
|
+
this.emit('solution:stored', { problemHash, contributor: contributorId });
|
|
827
|
+
|
|
828
|
+
return entry;
|
|
829
|
+
}
|
|
830
|
+
|
|
831
|
+
/**
|
|
832
|
+
* Query for a solution
|
|
833
|
+
*/
|
|
834
|
+
querySolution(problemHash) {
|
|
835
|
+
const entry = this.solutions.get(problemHash);
|
|
836
|
+
if (entry) {
|
|
837
|
+
entry.usageCount++;
|
|
838
|
+
}
|
|
839
|
+
return entry;
|
|
840
|
+
}
|
|
841
|
+
|
|
842
|
+
/**
|
|
843
|
+
* Store an optimization strategy
|
|
844
|
+
*/
|
|
845
|
+
storeOptimization(category, strategy, contributorId, improvement) {
|
|
846
|
+
const key = `${category}:${createHash('sha256').update(JSON.stringify(strategy)).digest('hex').slice(0, 8)}`;
|
|
847
|
+
|
|
848
|
+
const entry = {
|
|
849
|
+
key,
|
|
850
|
+
category,
|
|
851
|
+
strategy,
|
|
852
|
+
contributor: contributorId,
|
|
853
|
+
timestamp: Date.now(),
|
|
854
|
+
improvement,
|
|
855
|
+
adoptions: 0,
|
|
856
|
+
};
|
|
857
|
+
|
|
858
|
+
this.optimizations.set(key, entry);
|
|
859
|
+
this._trackContribution(contributorId);
|
|
860
|
+
this._pruneIfNeeded(this.optimizations);
|
|
861
|
+
|
|
862
|
+
this.emit('optimization:stored', { key, category, improvement });
|
|
863
|
+
|
|
864
|
+
return entry;
|
|
865
|
+
}
|
|
866
|
+
|
|
867
|
+
/**
|
|
868
|
+
* Broadcast a warning to the collective
|
|
869
|
+
*/
|
|
870
|
+
broadcastWarning(warningType, details, reporterId) {
|
|
871
|
+
const key = `${warningType}:${Date.now()}`;
|
|
872
|
+
|
|
873
|
+
const warning = {
|
|
874
|
+
key,
|
|
875
|
+
type: warningType,
|
|
876
|
+
details,
|
|
877
|
+
reporter: reporterId,
|
|
878
|
+
timestamp: Date.now(),
|
|
879
|
+
confirmations: [reporterId],
|
|
880
|
+
active: true,
|
|
881
|
+
};
|
|
882
|
+
|
|
883
|
+
this.warnings.set(key, warning);
|
|
884
|
+
this._trackContribution(reporterId);
|
|
885
|
+
|
|
886
|
+
this.emit('warning:broadcast', warning);
|
|
887
|
+
|
|
888
|
+
return warning;
|
|
889
|
+
}
|
|
890
|
+
|
|
891
|
+
/**
|
|
892
|
+
* Track contribution
|
|
893
|
+
* @private
|
|
894
|
+
*/
|
|
895
|
+
_trackContribution(networkId) {
|
|
896
|
+
const count = this.contributions.get(networkId) || 0;
|
|
897
|
+
this.contributions.set(networkId, count + 1);
|
|
898
|
+
}
|
|
899
|
+
|
|
900
|
+
/**
|
|
901
|
+
* Prune old entries if size exceeded
|
|
902
|
+
* @private
|
|
903
|
+
*/
|
|
904
|
+
_pruneIfNeeded(store) {
|
|
905
|
+
if (store.size <= this.config.maxMemorySize) return;
|
|
906
|
+
|
|
907
|
+
const cutoff = Date.now() - this.config.retentionMs;
|
|
908
|
+
const toDelete = [];
|
|
909
|
+
|
|
910
|
+
for (const [key, entry] of store) {
|
|
911
|
+
if (entry.timestamp < cutoff) {
|
|
912
|
+
toDelete.push(key);
|
|
913
|
+
}
|
|
914
|
+
}
|
|
915
|
+
|
|
916
|
+
// Delete oldest entries first
|
|
917
|
+
toDelete.forEach(key => store.delete(key));
|
|
918
|
+
|
|
919
|
+
// If still too large, delete least used
|
|
920
|
+
if (store.size > this.config.maxMemorySize) {
|
|
921
|
+
const entries = Array.from(store.entries())
|
|
922
|
+
.sort((a, b) => (a[1].usageCount || 0) - (b[1].usageCount || 0));
|
|
923
|
+
|
|
924
|
+
const excess = store.size - this.config.maxMemorySize;
|
|
925
|
+
for (let i = 0; i < excess; i++) {
|
|
926
|
+
store.delete(entries[i][0]);
|
|
927
|
+
}
|
|
928
|
+
}
|
|
929
|
+
}
|
|
930
|
+
|
|
931
|
+
/**
|
|
932
|
+
* Get memory statistics
|
|
933
|
+
*/
|
|
934
|
+
getStats() {
|
|
935
|
+
return {
|
|
936
|
+
patterns: this.patterns.size,
|
|
937
|
+
trustedPatterns: Array.from(this.patterns.values()).filter(p => p.trusted).length,
|
|
938
|
+
solutions: this.solutions.size,
|
|
939
|
+
optimizations: this.optimizations.size,
|
|
940
|
+
activeWarnings: Array.from(this.warnings.values()).filter(w => w.active).length,
|
|
941
|
+
topContributors: Array.from(this.contributions.entries())
|
|
942
|
+
.sort((a, b) => b[1] - a[1])
|
|
943
|
+
.slice(0, 10),
|
|
944
|
+
};
|
|
945
|
+
}
|
|
946
|
+
}
|
|
947
|
+
|
|
948
|
+
// ============================================
|
|
949
|
+
// MERKLE LINEAGE DAG
|
|
950
|
+
// ============================================
|
|
951
|
+
|
|
952
|
+
/**
|
|
953
|
+
* MerkleLineageDAG - Cryptographic proof of network ancestry
|
|
954
|
+
*
|
|
955
|
+
* Uses a Merkle DAG structure to provide:
|
|
956
|
+
* - Tamper-proof lineage verification
|
|
957
|
+
* - Efficient ancestry proofs
|
|
958
|
+
* - Quantum-resistant hash chains (SHA-3 ready)
|
|
959
|
+
*/
|
|
960
|
+
export class MerkleLineageDAG {
|
|
961
|
+
constructor(hashAlgorithm = 'sha256') {
|
|
962
|
+
this.hashAlgorithm = hashAlgorithm;
|
|
963
|
+
this.nodes = new Map(); // hash -> { data, parentHashes, childHashes }
|
|
964
|
+
this.roots = new Set(); // Genesis nodes (no parents)
|
|
965
|
+
}
|
|
966
|
+
|
|
967
|
+
/**
|
|
968
|
+
* Compute content-addressable hash
|
|
969
|
+
*/
|
|
970
|
+
computeHash(data) {
|
|
971
|
+
return createHash(this.hashAlgorithm)
|
|
972
|
+
.update(JSON.stringify(data))
|
|
973
|
+
.digest('hex');
|
|
974
|
+
}
|
|
975
|
+
|
|
976
|
+
/**
|
|
977
|
+
* Add a genesis node (root of lineage)
|
|
978
|
+
*/
|
|
979
|
+
addGenesisNode(networkId, genome) {
|
|
980
|
+
const data = {
|
|
981
|
+
type: 'genesis',
|
|
982
|
+
networkId,
|
|
983
|
+
genomeId: genome.id,
|
|
984
|
+
dnaChecksum: genome.dna.checksum,
|
|
985
|
+
creator: GENESIS_PRIME.id,
|
|
986
|
+
timestamp: Date.now(),
|
|
987
|
+
};
|
|
988
|
+
|
|
989
|
+
const hash = this.computeHash(data);
|
|
990
|
+
|
|
991
|
+
this.nodes.set(hash, {
|
|
992
|
+
hash,
|
|
993
|
+
data,
|
|
994
|
+
parentHashes: [],
|
|
995
|
+
childHashes: [],
|
|
996
|
+
});
|
|
997
|
+
|
|
998
|
+
this.roots.add(hash);
|
|
999
|
+
|
|
1000
|
+
return hash;
|
|
1001
|
+
}
|
|
1002
|
+
|
|
1003
|
+
/**
|
|
1004
|
+
* Add a child node (inherits from parent)
|
|
1005
|
+
*/
|
|
1006
|
+
addChildNode(networkId, genome, parentHash) {
|
|
1007
|
+
const parentNode = this.nodes.get(parentHash);
|
|
1008
|
+
if (!parentNode) {
|
|
1009
|
+
throw new Error(`Parent node not found: ${parentHash}`);
|
|
1010
|
+
}
|
|
1011
|
+
|
|
1012
|
+
const data = {
|
|
1013
|
+
type: 'child',
|
|
1014
|
+
networkId,
|
|
1015
|
+
genomeId: genome.id,
|
|
1016
|
+
dnaChecksum: genome.dna.checksum,
|
|
1017
|
+
parentHash,
|
|
1018
|
+
generation: genome.generation,
|
|
1019
|
+
timestamp: Date.now(),
|
|
1020
|
+
};
|
|
1021
|
+
|
|
1022
|
+
const hash = this.computeHash(data);
|
|
1023
|
+
|
|
1024
|
+
this.nodes.set(hash, {
|
|
1025
|
+
hash,
|
|
1026
|
+
data,
|
|
1027
|
+
parentHashes: [parentHash],
|
|
1028
|
+
childHashes: [],
|
|
1029
|
+
});
|
|
1030
|
+
|
|
1031
|
+
// Link parent to child
|
|
1032
|
+
parentNode.childHashes.push(hash);
|
|
1033
|
+
|
|
1034
|
+
return hash;
|
|
1035
|
+
}
|
|
1036
|
+
|
|
1037
|
+
/**
|
|
1038
|
+
* Generate ancestry proof (Merkle path from node to root)
|
|
1039
|
+
*/
|
|
1040
|
+
generateAncestryProof(nodeHash) {
|
|
1041
|
+
const proof = [];
|
|
1042
|
+
let currentHash = nodeHash;
|
|
1043
|
+
|
|
1044
|
+
while (currentHash) {
|
|
1045
|
+
const node = this.nodes.get(currentHash);
|
|
1046
|
+
if (!node) break;
|
|
1047
|
+
|
|
1048
|
+
proof.push({
|
|
1049
|
+
hash: node.hash,
|
|
1050
|
+
data: node.data,
|
|
1051
|
+
});
|
|
1052
|
+
|
|
1053
|
+
currentHash = node.parentHashes[0];
|
|
1054
|
+
}
|
|
1055
|
+
|
|
1056
|
+
return {
|
|
1057
|
+
nodeHash,
|
|
1058
|
+
proof,
|
|
1059
|
+
rootReached: proof.length > 0 && this.roots.has(proof[proof.length - 1].hash),
|
|
1060
|
+
proofLength: proof.length,
|
|
1061
|
+
};
|
|
1062
|
+
}
|
|
1063
|
+
|
|
1064
|
+
/**
|
|
1065
|
+
* Verify ancestry proof
|
|
1066
|
+
*/
|
|
1067
|
+
verifyAncestryProof(proof) {
|
|
1068
|
+
if (!proof || proof.proof.length === 0) return false;
|
|
1069
|
+
|
|
1070
|
+
// Verify hash chain
|
|
1071
|
+
for (let i = 0; i < proof.proof.length - 1; i++) {
|
|
1072
|
+
const current = proof.proof[i];
|
|
1073
|
+
const parent = proof.proof[i + 1];
|
|
1074
|
+
|
|
1075
|
+
// Verify hash matches data
|
|
1076
|
+
const computedHash = this.computeHash(current.data);
|
|
1077
|
+
if (computedHash !== current.hash) return false;
|
|
1078
|
+
|
|
1079
|
+
// Verify parent link
|
|
1080
|
+
if (current.data.parentHash !== parent.hash) return false;
|
|
1081
|
+
}
|
|
1082
|
+
|
|
1083
|
+
// Verify root is genesis
|
|
1084
|
+
const root = proof.proof[proof.proof.length - 1];
|
|
1085
|
+
return root.data.creator === GENESIS_PRIME.id;
|
|
1086
|
+
}
|
|
1087
|
+
|
|
1088
|
+
/**
|
|
1089
|
+
* Get all descendants of a node
|
|
1090
|
+
*/
|
|
1091
|
+
getDescendants(nodeHash, depth = Infinity) {
|
|
1092
|
+
const descendants = [];
|
|
1093
|
+
const visited = new Set();
|
|
1094
|
+
|
|
1095
|
+
const traverse = (hash, currentDepth) => {
|
|
1096
|
+
if (currentDepth > depth || visited.has(hash)) return;
|
|
1097
|
+
visited.add(hash);
|
|
1098
|
+
|
|
1099
|
+
const node = this.nodes.get(hash);
|
|
1100
|
+
if (!node) return;
|
|
1101
|
+
|
|
1102
|
+
for (const childHash of node.childHashes) {
|
|
1103
|
+
descendants.push(childHash);
|
|
1104
|
+
traverse(childHash, currentDepth + 1);
|
|
1105
|
+
}
|
|
1106
|
+
};
|
|
1107
|
+
|
|
1108
|
+
traverse(nodeHash, 0);
|
|
1109
|
+
return descendants;
|
|
1110
|
+
}
|
|
1111
|
+
|
|
1112
|
+
/**
|
|
1113
|
+
* Add a node (generic wrapper for addGenesisNode/addChildNode)
|
|
1114
|
+
* Called by NetworkGenesis.spawnGenesisNetwork() and reproduce()
|
|
1115
|
+
*/
|
|
1116
|
+
addNode(data) {
|
|
1117
|
+
const { networkId, parentId, generation, dna, name, mutations, createdAt } = data;
|
|
1118
|
+
|
|
1119
|
+
// Store networkId -> hash mapping for lookups
|
|
1120
|
+
if (!this.networkToHash) {
|
|
1121
|
+
this.networkToHash = new Map();
|
|
1122
|
+
}
|
|
1123
|
+
|
|
1124
|
+
// Is this a genesis node? (parent is GENESIS_PRIME)
|
|
1125
|
+
if (parentId === 'rUv' || parentId === GENESIS_PRIME.id) {
|
|
1126
|
+
const nodeData = {
|
|
1127
|
+
type: 'genesis',
|
|
1128
|
+
networkId,
|
|
1129
|
+
name,
|
|
1130
|
+
dnaChecksum: dna?.checksum || this.computeHash(dna),
|
|
1131
|
+
creator: GENESIS_PRIME.id,
|
|
1132
|
+
timestamp: createdAt || Date.now(),
|
|
1133
|
+
};
|
|
1134
|
+
|
|
1135
|
+
const hash = this.computeHash(nodeData);
|
|
1136
|
+
|
|
1137
|
+
this.nodes.set(hash, {
|
|
1138
|
+
hash,
|
|
1139
|
+
data: nodeData,
|
|
1140
|
+
networkId,
|
|
1141
|
+
parentHashes: [],
|
|
1142
|
+
childHashes: [],
|
|
1143
|
+
});
|
|
1144
|
+
|
|
1145
|
+
this.roots.add(hash);
|
|
1146
|
+
this.networkToHash.set(networkId, hash);
|
|
1147
|
+
|
|
1148
|
+
return { hash, ...nodeData };
|
|
1149
|
+
}
|
|
1150
|
+
|
|
1151
|
+
// Child node - look up parent hash
|
|
1152
|
+
const parentHash = this.networkToHash.get(parentId);
|
|
1153
|
+
if (!parentHash) {
|
|
1154
|
+
// Parent not in DAG - create as orphan root
|
|
1155
|
+
const nodeData = {
|
|
1156
|
+
type: 'orphan',
|
|
1157
|
+
networkId,
|
|
1158
|
+
name,
|
|
1159
|
+
parentId,
|
|
1160
|
+
generation,
|
|
1161
|
+
dnaChecksum: dna?.checksum || this.computeHash(dna),
|
|
1162
|
+
mutations: mutations || {},
|
|
1163
|
+
timestamp: createdAt || Date.now(),
|
|
1164
|
+
};
|
|
1165
|
+
|
|
1166
|
+
const hash = this.computeHash(nodeData);
|
|
1167
|
+
|
|
1168
|
+
this.nodes.set(hash, {
|
|
1169
|
+
hash,
|
|
1170
|
+
data: nodeData,
|
|
1171
|
+
networkId,
|
|
1172
|
+
parentHashes: [],
|
|
1173
|
+
childHashes: [],
|
|
1174
|
+
});
|
|
1175
|
+
|
|
1176
|
+
this.networkToHash.set(networkId, hash);
|
|
1177
|
+
|
|
1178
|
+
return { hash, ...nodeData };
|
|
1179
|
+
}
|
|
1180
|
+
|
|
1181
|
+
const parentNode = this.nodes.get(parentHash);
|
|
1182
|
+
const nodeData = {
|
|
1183
|
+
type: 'child',
|
|
1184
|
+
networkId,
|
|
1185
|
+
name,
|
|
1186
|
+
parentId,
|
|
1187
|
+
parentHash,
|
|
1188
|
+
generation,
|
|
1189
|
+
dnaChecksum: dna?.checksum || this.computeHash(dna),
|
|
1190
|
+
mutations: mutations || {},
|
|
1191
|
+
timestamp: createdAt || Date.now(),
|
|
1192
|
+
};
|
|
1193
|
+
|
|
1194
|
+
const hash = this.computeHash(nodeData);
|
|
1195
|
+
|
|
1196
|
+
this.nodes.set(hash, {
|
|
1197
|
+
hash,
|
|
1198
|
+
data: nodeData,
|
|
1199
|
+
networkId,
|
|
1200
|
+
parentHashes: [parentHash],
|
|
1201
|
+
childHashes: [],
|
|
1202
|
+
});
|
|
1203
|
+
|
|
1204
|
+
// Link parent to child
|
|
1205
|
+
if (parentNode) {
|
|
1206
|
+
parentNode.childHashes.push(hash);
|
|
1207
|
+
}
|
|
1208
|
+
|
|
1209
|
+
this.networkToHash.set(networkId, hash);
|
|
1210
|
+
|
|
1211
|
+
return { hash, ...nodeData };
|
|
1212
|
+
}
|
|
1213
|
+
|
|
1214
|
+
/**
|
|
1215
|
+
* Get ancestry path from a network to genesis
|
|
1216
|
+
*/
|
|
1217
|
+
getAncestryPath(networkId) {
|
|
1218
|
+
if (!this.networkToHash) return [];
|
|
1219
|
+
|
|
1220
|
+
const hash = this.networkToHash.get(networkId);
|
|
1221
|
+
if (!hash) return [];
|
|
1222
|
+
|
|
1223
|
+
const path = [];
|
|
1224
|
+
let currentHash = hash;
|
|
1225
|
+
|
|
1226
|
+
while (currentHash) {
|
|
1227
|
+
const node = this.nodes.get(currentHash);
|
|
1228
|
+
if (!node) break;
|
|
1229
|
+
|
|
1230
|
+
path.push({
|
|
1231
|
+
networkId: node.networkId,
|
|
1232
|
+
hash: node.hash,
|
|
1233
|
+
type: node.data.type,
|
|
1234
|
+
generation: node.data.generation,
|
|
1235
|
+
});
|
|
1236
|
+
|
|
1237
|
+
currentHash = node.parentHashes[0];
|
|
1238
|
+
}
|
|
1239
|
+
|
|
1240
|
+
return path;
|
|
1241
|
+
}
|
|
1242
|
+
|
|
1243
|
+
/**
|
|
1244
|
+
* Verify ancestry - check if a network descends from an ancestor
|
|
1245
|
+
*/
|
|
1246
|
+
verifyAncestry(networkId, ancestorId) {
|
|
1247
|
+
const path = this.getAncestryPath(networkId);
|
|
1248
|
+
|
|
1249
|
+
// Check if we reach genesis (rUv)
|
|
1250
|
+
if (ancestorId === 'rUv' || ancestorId === GENESIS_PRIME.id) {
|
|
1251
|
+
return path.some(node => node.type === 'genesis');
|
|
1252
|
+
}
|
|
1253
|
+
|
|
1254
|
+
// Check if we pass through the ancestor
|
|
1255
|
+
return path.some(node => node.networkId === ancestorId);
|
|
1256
|
+
}
|
|
1257
|
+
|
|
1258
|
+
/**
|
|
1259
|
+
* Get the Merkle root of the lineage DAG
|
|
1260
|
+
*/
|
|
1261
|
+
getMerkleRoot() {
|
|
1262
|
+
if (this.nodes.size === 0) return null;
|
|
1263
|
+
|
|
1264
|
+
// Collect all node hashes
|
|
1265
|
+
const hashes = Array.from(this.nodes.keys()).sort();
|
|
1266
|
+
|
|
1267
|
+
// Build Merkle tree
|
|
1268
|
+
if (hashes.length === 1) return hashes[0];
|
|
1269
|
+
|
|
1270
|
+
let level = hashes;
|
|
1271
|
+
while (level.length > 1) {
|
|
1272
|
+
const nextLevel = [];
|
|
1273
|
+
for (let i = 0; i < level.length; i += 2) {
|
|
1274
|
+
if (i + 1 < level.length) {
|
|
1275
|
+
const combined = this.computeHash(level[i] + level[i + 1]);
|
|
1276
|
+
nextLevel.push(combined);
|
|
1277
|
+
} else {
|
|
1278
|
+
nextLevel.push(level[i]);
|
|
1279
|
+
}
|
|
1280
|
+
}
|
|
1281
|
+
level = nextLevel;
|
|
1282
|
+
}
|
|
1283
|
+
|
|
1284
|
+
return level[0];
|
|
1285
|
+
}
|
|
1286
|
+
|
|
1287
|
+
/**
|
|
1288
|
+
* Get DAG statistics
|
|
1289
|
+
*/
|
|
1290
|
+
getStats() {
|
|
1291
|
+
let maxDepth = 0;
|
|
1292
|
+
let totalNodes = this.nodes.size;
|
|
1293
|
+
|
|
1294
|
+
// Calculate max depth
|
|
1295
|
+
for (const rootHash of this.roots) {
|
|
1296
|
+
const depth = this._calculateDepth(rootHash);
|
|
1297
|
+
maxDepth = Math.max(maxDepth, depth);
|
|
1298
|
+
}
|
|
1299
|
+
|
|
1300
|
+
return {
|
|
1301
|
+
totalNodes,
|
|
1302
|
+
rootCount: this.roots.size,
|
|
1303
|
+
maxDepth,
|
|
1304
|
+
};
|
|
1305
|
+
}
|
|
1306
|
+
|
|
1307
|
+
/**
|
|
1308
|
+
* Calculate depth from a node
|
|
1309
|
+
* @private
|
|
1310
|
+
*/
|
|
1311
|
+
_calculateDepth(hash, visited = new Set()) {
|
|
1312
|
+
if (visited.has(hash)) return 0;
|
|
1313
|
+
visited.add(hash);
|
|
1314
|
+
|
|
1315
|
+
const node = this.nodes.get(hash);
|
|
1316
|
+
if (!node || node.childHashes.length === 0) return 1;
|
|
1317
|
+
|
|
1318
|
+
let maxChildDepth = 0;
|
|
1319
|
+
for (const childHash of node.childHashes) {
|
|
1320
|
+
maxChildDepth = Math.max(maxChildDepth, this._calculateDepth(childHash, visited));
|
|
1321
|
+
}
|
|
1322
|
+
|
|
1323
|
+
return 1 + maxChildDepth;
|
|
1324
|
+
}
|
|
1325
|
+
}
|
|
1326
|
+
|
|
1327
|
+
// ============================================
|
|
1328
|
+
// GOSSIP PROTOCOL
|
|
1329
|
+
// ============================================
|
|
1330
|
+
|
|
1331
|
+
/**
|
|
1332
|
+
* GossipProtocol - Epidemic-style information propagation
|
|
1333
|
+
*
|
|
1334
|
+
* Enables:
|
|
1335
|
+
* - Decentralized network discovery
|
|
1336
|
+
* - Knowledge propagation across lineage
|
|
1337
|
+
* - Failure detection and notification
|
|
1338
|
+
* - Rumor-based consensus preparation
|
|
1339
|
+
*/
|
|
1340
|
+
export class GossipProtocol extends EventEmitter {
|
|
1341
|
+
constructor(localNetworkId, options = {}) {
|
|
1342
|
+
super();
|
|
1343
|
+
|
|
1344
|
+
this.localNetworkId = localNetworkId;
|
|
1345
|
+
|
|
1346
|
+
this.config = {
|
|
1347
|
+
fanout: options.fanout ?? 3, // Number of peers to gossip to
|
|
1348
|
+
gossipIntervalMs: options.gossipIntervalMs ?? 1000,
|
|
1349
|
+
maxRumors: options.maxRumors ?? 1000,
|
|
1350
|
+
rumorTTL: options.rumorTTL ?? 10, // Max hops
|
|
1351
|
+
antiEntropyIntervalMs: options.antiEntropyIntervalMs ?? 30000,
|
|
1352
|
+
};
|
|
1353
|
+
|
|
1354
|
+
// Peer registry
|
|
1355
|
+
this.peers = new Map(); // peerId -> { lastSeen, vectorClock, status }
|
|
1356
|
+
|
|
1357
|
+
// Rumor store (CRDT-like)
|
|
1358
|
+
this.rumors = new Map(); // rumorId -> { data, vectorClock, seenBy, ttl }
|
|
1359
|
+
|
|
1360
|
+
// Vector clock for causal ordering
|
|
1361
|
+
this.vectorClock = new Map(); // peerId -> logicalTime
|
|
1362
|
+
|
|
1363
|
+
// Heartbeat tracking
|
|
1364
|
+
this.heartbeats = new Map(); // peerId -> { generation, timestamp }
|
|
1365
|
+
}
|
|
1366
|
+
|
|
1367
|
+
/**
|
|
1368
|
+
* Add a peer to gossip with
|
|
1369
|
+
*/
|
|
1370
|
+
addPeer(peerId, channel) {
|
|
1371
|
+
this.peers.set(peerId, {
|
|
1372
|
+
channel,
|
|
1373
|
+
lastSeen: Date.now(),
|
|
1374
|
+
vectorClock: new Map(),
|
|
1375
|
+
status: 'alive',
|
|
1376
|
+
suspicionLevel: 0,
|
|
1377
|
+
});
|
|
1378
|
+
|
|
1379
|
+
this.vectorClock.set(peerId, 0);
|
|
1380
|
+
|
|
1381
|
+
this.emit('peer:added', { peerId });
|
|
1382
|
+
}
|
|
1383
|
+
|
|
1384
|
+
/**
|
|
1385
|
+
* Remove a peer
|
|
1386
|
+
*/
|
|
1387
|
+
removePeer(peerId) {
|
|
1388
|
+
this.peers.delete(peerId);
|
|
1389
|
+
this.emit('peer:removed', { peerId });
|
|
1390
|
+
}
|
|
1391
|
+
|
|
1392
|
+
/**
|
|
1393
|
+
* Increment local vector clock
|
|
1394
|
+
*/
|
|
1395
|
+
tick() {
|
|
1396
|
+
const current = this.vectorClock.get(this.localNetworkId) || 0;
|
|
1397
|
+
this.vectorClock.set(this.localNetworkId, current + 1);
|
|
1398
|
+
return current + 1;
|
|
1399
|
+
}
|
|
1400
|
+
|
|
1401
|
+
/**
|
|
1402
|
+
* Merge vector clocks (for causal ordering)
|
|
1403
|
+
*/
|
|
1404
|
+
mergeVectorClock(remoteClock) {
|
|
1405
|
+
for (const [peerId, time] of remoteClock) {
|
|
1406
|
+
const local = this.vectorClock.get(peerId) || 0;
|
|
1407
|
+
this.vectorClock.set(peerId, Math.max(local, time));
|
|
1408
|
+
}
|
|
1409
|
+
}
|
|
1410
|
+
|
|
1411
|
+
/**
|
|
1412
|
+
* Create and spread a rumor
|
|
1413
|
+
*/
|
|
1414
|
+
spreadRumor(type, data) {
|
|
1415
|
+
this.tick();
|
|
1416
|
+
|
|
1417
|
+
const rumorId = `${this.localNetworkId}-${Date.now()}-${randomBytes(4).toString('hex')}`;
|
|
1418
|
+
|
|
1419
|
+
const rumor = {
|
|
1420
|
+
id: rumorId,
|
|
1421
|
+
type,
|
|
1422
|
+
data,
|
|
1423
|
+
origin: this.localNetworkId,
|
|
1424
|
+
vectorClock: new Map(this.vectorClock),
|
|
1425
|
+
seenBy: new Set([this.localNetworkId]),
|
|
1426
|
+
ttl: this.config.rumorTTL,
|
|
1427
|
+
createdAt: Date.now(),
|
|
1428
|
+
};
|
|
1429
|
+
|
|
1430
|
+
this.rumors.set(rumorId, rumor);
|
|
1431
|
+
|
|
1432
|
+
// Prune old rumors
|
|
1433
|
+
this._pruneRumors();
|
|
1434
|
+
|
|
1435
|
+
// Gossip to random peers
|
|
1436
|
+
this._gossipToPeers(rumor);
|
|
1437
|
+
|
|
1438
|
+
this.emit('rumor:created', { rumorId, type });
|
|
1439
|
+
|
|
1440
|
+
return rumor;
|
|
1441
|
+
}
|
|
1442
|
+
|
|
1443
|
+
/**
|
|
1444
|
+
* Receive a rumor from another peer
|
|
1445
|
+
*/
|
|
1446
|
+
receiveRumor(rumor, fromPeerId) {
|
|
1447
|
+
// Update peer last seen
|
|
1448
|
+
const peer = this.peers.get(fromPeerId);
|
|
1449
|
+
if (peer) {
|
|
1450
|
+
peer.lastSeen = Date.now();
|
|
1451
|
+
peer.status = 'alive';
|
|
1452
|
+
peer.suspicionLevel = 0;
|
|
1453
|
+
}
|
|
1454
|
+
|
|
1455
|
+
// Merge vector clock
|
|
1456
|
+
this.mergeVectorClock(rumor.vectorClock);
|
|
1457
|
+
|
|
1458
|
+
// Check if we've seen this rumor
|
|
1459
|
+
const existing = this.rumors.get(rumor.id);
|
|
1460
|
+
if (existing) {
|
|
1461
|
+
// Merge seen-by sets (CRDT merge)
|
|
1462
|
+
for (const seenBy of rumor.seenBy) {
|
|
1463
|
+
existing.seenBy.add(seenBy);
|
|
1464
|
+
}
|
|
1465
|
+
return { new: false, rumorId: rumor.id };
|
|
1466
|
+
}
|
|
1467
|
+
|
|
1468
|
+
// New rumor - store and propagate
|
|
1469
|
+
rumor.seenBy.add(this.localNetworkId);
|
|
1470
|
+
rumor.ttl--;
|
|
1471
|
+
|
|
1472
|
+
this.rumors.set(rumor.id, rumor);
|
|
1473
|
+
|
|
1474
|
+
this.emit('rumor:received', {
|
|
1475
|
+
rumorId: rumor.id,
|
|
1476
|
+
type: rumor.type,
|
|
1477
|
+
from: fromPeerId,
|
|
1478
|
+
});
|
|
1479
|
+
|
|
1480
|
+
// Continue propagation if TTL > 0
|
|
1481
|
+
if (rumor.ttl > 0) {
|
|
1482
|
+
this._gossipToPeers(rumor, [fromPeerId]);
|
|
1483
|
+
}
|
|
1484
|
+
|
|
1485
|
+
return { new: true, rumorId: rumor.id };
|
|
1486
|
+
}
|
|
1487
|
+
|
|
1488
|
+
/**
|
|
1489
|
+
* Gossip to random peers
|
|
1490
|
+
* @private
|
|
1491
|
+
*/
|
|
1492
|
+
_gossipToPeers(rumor, exclude = []) {
|
|
1493
|
+
const eligiblePeers = Array.from(this.peers.entries())
|
|
1494
|
+
.filter(([id, p]) => !exclude.includes(id) && !rumor.seenBy.has(id) && p.status === 'alive');
|
|
1495
|
+
|
|
1496
|
+
// Random selection (fanout)
|
|
1497
|
+
const selected = this._randomSample(eligiblePeers, this.config.fanout);
|
|
1498
|
+
|
|
1499
|
+
for (const [peerId, peer] of selected) {
|
|
1500
|
+
this.emit('gossip:send', {
|
|
1501
|
+
to: peerId,
|
|
1502
|
+
rumor,
|
|
1503
|
+
});
|
|
1504
|
+
}
|
|
1505
|
+
}
|
|
1506
|
+
|
|
1507
|
+
/**
|
|
1508
|
+
* Random sample from array
|
|
1509
|
+
* @private
|
|
1510
|
+
*/
|
|
1511
|
+
_randomSample(array, n) {
|
|
1512
|
+
const shuffled = [...array].sort(() => Math.random() - 0.5);
|
|
1513
|
+
return shuffled.slice(0, n);
|
|
1514
|
+
}
|
|
1515
|
+
|
|
1516
|
+
/**
|
|
1517
|
+
* Prune old rumors
|
|
1518
|
+
* @private
|
|
1519
|
+
*/
|
|
1520
|
+
_pruneRumors() {
|
|
1521
|
+
if (this.rumors.size <= this.config.maxRumors) return;
|
|
1522
|
+
|
|
1523
|
+
// Remove oldest rumors
|
|
1524
|
+
const sorted = Array.from(this.rumors.entries())
|
|
1525
|
+
.sort((a, b) => a[1].createdAt - b[1].createdAt);
|
|
1526
|
+
|
|
1527
|
+
const toRemove = sorted.slice(0, sorted.length - this.config.maxRumors);
|
|
1528
|
+
for (const [id] of toRemove) {
|
|
1529
|
+
this.rumors.delete(id);
|
|
1530
|
+
}
|
|
1531
|
+
}
|
|
1532
|
+
|
|
1533
|
+
/**
|
|
1534
|
+
* Send heartbeat
|
|
1535
|
+
*/
|
|
1536
|
+
sendHeartbeat() {
|
|
1537
|
+
const generation = this.heartbeats.get(this.localNetworkId)?.generation ?? 0;
|
|
1538
|
+
|
|
1539
|
+
this.spreadRumor('heartbeat', {
|
|
1540
|
+
networkId: this.localNetworkId,
|
|
1541
|
+
generation: generation + 1,
|
|
1542
|
+
timestamp: Date.now(),
|
|
1543
|
+
});
|
|
1544
|
+
|
|
1545
|
+
this.heartbeats.set(this.localNetworkId, {
|
|
1546
|
+
generation: generation + 1,
|
|
1547
|
+
timestamp: Date.now(),
|
|
1548
|
+
});
|
|
1549
|
+
}
|
|
1550
|
+
|
|
1551
|
+
/**
|
|
1552
|
+
* Detect failed peers (SWIM-style)
|
|
1553
|
+
*/
|
|
1554
|
+
detectFailures() {
|
|
1555
|
+
const now = Date.now();
|
|
1556
|
+
const failures = [];
|
|
1557
|
+
|
|
1558
|
+
for (const [peerId, peer] of this.peers) {
|
|
1559
|
+
const timeSinceLastSeen = now - peer.lastSeen;
|
|
1560
|
+
|
|
1561
|
+
if (timeSinceLastSeen > this.config.gossipIntervalMs * 5) {
|
|
1562
|
+
peer.suspicionLevel++;
|
|
1563
|
+
|
|
1564
|
+
if (peer.suspicionLevel >= 3) {
|
|
1565
|
+
peer.status = 'suspected';
|
|
1566
|
+
|
|
1567
|
+
if (peer.suspicionLevel >= 5) {
|
|
1568
|
+
peer.status = 'failed';
|
|
1569
|
+
failures.push(peerId);
|
|
1570
|
+
}
|
|
1571
|
+
}
|
|
1572
|
+
}
|
|
1573
|
+
}
|
|
1574
|
+
|
|
1575
|
+
if (failures.length > 0) {
|
|
1576
|
+
this.emit('peers:failed', { failures });
|
|
1577
|
+
}
|
|
1578
|
+
|
|
1579
|
+
return failures;
|
|
1580
|
+
}
|
|
1581
|
+
|
|
1582
|
+
/**
|
|
1583
|
+
* Get protocol statistics
|
|
1584
|
+
*/
|
|
1585
|
+
getStats() {
|
|
1586
|
+
const statusCounts = { alive: 0, suspected: 0, failed: 0 };
|
|
1587
|
+
for (const peer of this.peers.values()) {
|
|
1588
|
+
statusCounts[peer.status]++;
|
|
1589
|
+
}
|
|
1590
|
+
|
|
1591
|
+
return {
|
|
1592
|
+
localNetworkId: this.localNetworkId,
|
|
1593
|
+
peerCount: this.peers.size,
|
|
1594
|
+
peerStatus: statusCounts,
|
|
1595
|
+
rumorCount: this.rumors.size,
|
|
1596
|
+
vectorClockSize: this.vectorClock.size,
|
|
1597
|
+
};
|
|
1598
|
+
}
|
|
1599
|
+
}
|
|
1600
|
+
|
|
1601
|
+
// ============================================
|
|
1602
|
+
// SWARM CONSENSUS
|
|
1603
|
+
// ============================================
|
|
1604
|
+
|
|
1605
|
+
/**
|
|
1606
|
+
* SwarmConsensus - Byzantine fault-tolerant collective decision making
|
|
1607
|
+
*
|
|
1608
|
+
* Combines:
|
|
1609
|
+
* - PBFT-inspired three-phase protocol
|
|
1610
|
+
* - Swarm intelligence for optimization
|
|
1611
|
+
* - Stigmergic coordination
|
|
1612
|
+
*/
|
|
1613
|
+
export class SwarmConsensus extends EventEmitter {
|
|
1614
|
+
constructor(localNetworkId, options = {}) {
|
|
1615
|
+
super();
|
|
1616
|
+
|
|
1617
|
+
this.localNetworkId = localNetworkId;
|
|
1618
|
+
|
|
1619
|
+
this.config = {
|
|
1620
|
+
minQuorum: options.minQuorum ?? 0.67, // 2/3 + 1
|
|
1621
|
+
maxRounds: options.maxRounds ?? 10,
|
|
1622
|
+
roundTimeoutMs: options.roundTimeoutMs ?? 5000,
|
|
1623
|
+
byzantineTolerance: options.byzantineTolerance ?? 0.33, // f < n/3
|
|
1624
|
+
};
|
|
1625
|
+
|
|
1626
|
+
// Active proposals
|
|
1627
|
+
this.proposals = new Map(); // proposalId -> ProposalState
|
|
1628
|
+
|
|
1629
|
+
// Pheromone trails (stigmergic memory)
|
|
1630
|
+
this.pheromones = new Map(); // decisionType -> { options: Map<optionId, strength> }
|
|
1631
|
+
}
|
|
1632
|
+
|
|
1633
|
+
/**
|
|
1634
|
+
* Propose a decision to the swarm
|
|
1635
|
+
*/
|
|
1636
|
+
propose(decisionType, options, metadata = {}) {
|
|
1637
|
+
const proposalId = `${this.localNetworkId}-${Date.now()}-${randomBytes(4).toString('hex')}`;
|
|
1638
|
+
|
|
1639
|
+
const proposal = {
|
|
1640
|
+
id: proposalId,
|
|
1641
|
+
type: decisionType,
|
|
1642
|
+
options, // Array of possible choices
|
|
1643
|
+
proposer: this.localNetworkId,
|
|
1644
|
+
metadata,
|
|
1645
|
+
createdAt: Date.now(),
|
|
1646
|
+
phase: 'pre-prepare', // pre-prepare | prepare | commit | decided
|
|
1647
|
+
votes: new Map(), // networkId -> { option, signature, timestamp }
|
|
1648
|
+
round: 0,
|
|
1649
|
+
decided: false,
|
|
1650
|
+
decision: null,
|
|
1651
|
+
};
|
|
1652
|
+
|
|
1653
|
+
this.proposals.set(proposalId, proposal);
|
|
1654
|
+
|
|
1655
|
+
this.emit('proposal:created', { proposalId, type: decisionType });
|
|
1656
|
+
|
|
1657
|
+
return proposal;
|
|
1658
|
+
}
|
|
1659
|
+
|
|
1660
|
+
/**
|
|
1661
|
+
* Vote on a proposal
|
|
1662
|
+
*/
|
|
1663
|
+
vote(proposalId, option, signature = null) {
|
|
1664
|
+
const proposal = this.proposals.get(proposalId);
|
|
1665
|
+
if (!proposal) {
|
|
1666
|
+
throw new Error(`Proposal not found: ${proposalId}`);
|
|
1667
|
+
}
|
|
1668
|
+
|
|
1669
|
+
if (proposal.decided) {
|
|
1670
|
+
return { success: false, reason: 'Already decided' };
|
|
1671
|
+
}
|
|
1672
|
+
|
|
1673
|
+
// Record vote
|
|
1674
|
+
proposal.votes.set(this.localNetworkId, {
|
|
1675
|
+
option,
|
|
1676
|
+
signature,
|
|
1677
|
+
timestamp: Date.now(),
|
|
1678
|
+
});
|
|
1679
|
+
|
|
1680
|
+
// Check for quorum
|
|
1681
|
+
this._checkQuorum(proposal);
|
|
1682
|
+
|
|
1683
|
+
this.emit('vote:cast', {
|
|
1684
|
+
proposalId,
|
|
1685
|
+
voter: this.localNetworkId,
|
|
1686
|
+
option,
|
|
1687
|
+
});
|
|
1688
|
+
|
|
1689
|
+
return { success: true, proposalId };
|
|
1690
|
+
}
|
|
1691
|
+
|
|
1692
|
+
/**
|
|
1693
|
+
* Receive vote from another network
|
|
1694
|
+
*/
|
|
1695
|
+
receiveVote(proposalId, voterId, option, signature) {
|
|
1696
|
+
const proposal = this.proposals.get(proposalId);
|
|
1697
|
+
if (!proposal || proposal.decided) return;
|
|
1698
|
+
|
|
1699
|
+
proposal.votes.set(voterId, {
|
|
1700
|
+
option,
|
|
1701
|
+
signature,
|
|
1702
|
+
timestamp: Date.now(),
|
|
1703
|
+
});
|
|
1704
|
+
|
|
1705
|
+
this._checkQuorum(proposal);
|
|
1706
|
+
}
|
|
1707
|
+
|
|
1708
|
+
/**
|
|
1709
|
+
* Check for quorum and advance phase
|
|
1710
|
+
* @private
|
|
1711
|
+
*/
|
|
1712
|
+
_checkQuorum(proposal) {
|
|
1713
|
+
const voteCount = proposal.votes.size;
|
|
1714
|
+
const optionCounts = new Map();
|
|
1715
|
+
|
|
1716
|
+
// Count votes per option
|
|
1717
|
+
for (const [, vote] of proposal.votes) {
|
|
1718
|
+
const count = optionCounts.get(vote.option) || 0;
|
|
1719
|
+
optionCounts.set(vote.option, count + 1);
|
|
1720
|
+
}
|
|
1721
|
+
|
|
1722
|
+
// Find majority option
|
|
1723
|
+
let maxVotes = 0;
|
|
1724
|
+
let majorityOption = null;
|
|
1725
|
+
|
|
1726
|
+
for (const [option, count] of optionCounts) {
|
|
1727
|
+
if (count > maxVotes) {
|
|
1728
|
+
maxVotes = count;
|
|
1729
|
+
majorityOption = option;
|
|
1730
|
+
}
|
|
1731
|
+
}
|
|
1732
|
+
|
|
1733
|
+
// Check if quorum reached
|
|
1734
|
+
// Note: In real implementation, need to know total participants
|
|
1735
|
+
// For now, use vote count as proxy
|
|
1736
|
+
const quorumSize = Math.ceil(voteCount * this.config.minQuorum);
|
|
1737
|
+
|
|
1738
|
+
if (maxVotes >= quorumSize && proposal.phase !== 'decided') {
|
|
1739
|
+
this._advancePhase(proposal, majorityOption);
|
|
1740
|
+
}
|
|
1741
|
+
}
|
|
1742
|
+
|
|
1743
|
+
/**
|
|
1744
|
+
* Advance proposal phase
|
|
1745
|
+
* @private
|
|
1746
|
+
*/
|
|
1747
|
+
_advancePhase(proposal, leadingOption) {
|
|
1748
|
+
switch (proposal.phase) {
|
|
1749
|
+
case 'pre-prepare':
|
|
1750
|
+
proposal.phase = 'prepare';
|
|
1751
|
+
this.emit('phase:prepare', { proposalId: proposal.id });
|
|
1752
|
+
break;
|
|
1753
|
+
|
|
1754
|
+
case 'prepare':
|
|
1755
|
+
proposal.phase = 'commit';
|
|
1756
|
+
this.emit('phase:commit', { proposalId: proposal.id });
|
|
1757
|
+
break;
|
|
1758
|
+
|
|
1759
|
+
case 'commit':
|
|
1760
|
+
proposal.phase = 'decided';
|
|
1761
|
+
proposal.decided = true;
|
|
1762
|
+
proposal.decision = leadingOption;
|
|
1763
|
+
proposal.decidedAt = Date.now();
|
|
1764
|
+
|
|
1765
|
+
// Update pheromone trails
|
|
1766
|
+
this._updatePheromones(proposal.type, leadingOption);
|
|
1767
|
+
|
|
1768
|
+
this.emit('decision:reached', {
|
|
1769
|
+
proposalId: proposal.id,
|
|
1770
|
+
decision: leadingOption,
|
|
1771
|
+
voteCount: proposal.votes.size,
|
|
1772
|
+
});
|
|
1773
|
+
break;
|
|
1774
|
+
}
|
|
1775
|
+
}
|
|
1776
|
+
|
|
1777
|
+
/**
|
|
1778
|
+
* Update pheromone trails (stigmergic learning)
|
|
1779
|
+
* @private
|
|
1780
|
+
*/
|
|
1781
|
+
_updatePheromones(decisionType, chosenOption) {
|
|
1782
|
+
if (!this.pheromones.has(decisionType)) {
|
|
1783
|
+
this.pheromones.set(decisionType, new Map());
|
|
1784
|
+
}
|
|
1785
|
+
|
|
1786
|
+
const trails = this.pheromones.get(decisionType);
|
|
1787
|
+
const currentStrength = trails.get(chosenOption) || 0;
|
|
1788
|
+
|
|
1789
|
+
// Reinforce chosen option
|
|
1790
|
+
trails.set(chosenOption, currentStrength + 1);
|
|
1791
|
+
|
|
1792
|
+
// Evaporate other trails (decay)
|
|
1793
|
+
for (const [option, strength] of trails) {
|
|
1794
|
+
if (option !== chosenOption) {
|
|
1795
|
+
trails.set(option, Math.max(0, strength * 0.9));
|
|
1796
|
+
}
|
|
1797
|
+
}
|
|
1798
|
+
}
|
|
1799
|
+
|
|
1800
|
+
/**
|
|
1801
|
+
* Get pheromone-guided suggestion (swarm wisdom)
|
|
1802
|
+
*/
|
|
1803
|
+
getSuggestion(decisionType) {
|
|
1804
|
+
const trails = this.pheromones.get(decisionType);
|
|
1805
|
+
if (!trails || trails.size === 0) return null;
|
|
1806
|
+
|
|
1807
|
+
// Probabilistic selection based on pheromone strength
|
|
1808
|
+
const total = Array.from(trails.values()).reduce((a, b) => a + b, 0);
|
|
1809
|
+
if (total === 0) return null;
|
|
1810
|
+
|
|
1811
|
+
const random = Math.random() * total;
|
|
1812
|
+
let cumulative = 0;
|
|
1813
|
+
|
|
1814
|
+
for (const [option, strength] of trails) {
|
|
1815
|
+
cumulative += strength;
|
|
1816
|
+
if (random <= cumulative) {
|
|
1817
|
+
return { option, confidence: strength / total };
|
|
1818
|
+
}
|
|
1819
|
+
}
|
|
1820
|
+
|
|
1821
|
+
return null;
|
|
1822
|
+
}
|
|
1823
|
+
|
|
1824
|
+
/**
|
|
1825
|
+
* Get consensus statistics
|
|
1826
|
+
*/
|
|
1827
|
+
getStats() {
|
|
1828
|
+
const decided = Array.from(this.proposals.values()).filter(p => p.decided).length;
|
|
1829
|
+
|
|
1830
|
+
return {
|
|
1831
|
+
activeProposals: this.proposals.size - decided,
|
|
1832
|
+
decidedProposals: decided,
|
|
1833
|
+
pheromoneTypes: this.pheromones.size,
|
|
1834
|
+
};
|
|
1835
|
+
}
|
|
1836
|
+
|
|
1837
|
+
/**
|
|
1838
|
+
* Create a proposal with participant voters (compatibility wrapper)
|
|
1839
|
+
*/
|
|
1840
|
+
createProposal(proposalId, type, data, voters) {
|
|
1841
|
+
const proposal = this.propose(type, [true, false], { proposalId, data, voters });
|
|
1842
|
+
|
|
1843
|
+
// Remove old entry and re-store with custom ID
|
|
1844
|
+
const oldId = proposal.id;
|
|
1845
|
+
this.proposals.delete(oldId);
|
|
1846
|
+
|
|
1847
|
+
proposal.id = proposalId;
|
|
1848
|
+
proposal.voters = new Set(voters);
|
|
1849
|
+
this.proposals.set(proposalId, proposal);
|
|
1850
|
+
|
|
1851
|
+
return proposal;
|
|
1852
|
+
}
|
|
1853
|
+
|
|
1854
|
+
/**
|
|
1855
|
+
* Check consensus status for a proposal
|
|
1856
|
+
*/
|
|
1857
|
+
checkConsensus(proposalId) {
|
|
1858
|
+
const proposal = this.proposals.get(proposalId);
|
|
1859
|
+
if (!proposal) {
|
|
1860
|
+
return { found: false, proposalId };
|
|
1861
|
+
}
|
|
1862
|
+
|
|
1863
|
+
const voteCounts = { true: 0, false: 0 };
|
|
1864
|
+
for (const [, vote] of proposal.votes) {
|
|
1865
|
+
const key = vote.option ? 'true' : 'false';
|
|
1866
|
+
voteCounts[key]++;
|
|
1867
|
+
}
|
|
1868
|
+
|
|
1869
|
+
const totalVotes = proposal.votes.size;
|
|
1870
|
+
const totalVoters = proposal.voters?.size || 3;
|
|
1871
|
+
const threshold = Math.ceil(totalVoters * this.config.minQuorum);
|
|
1872
|
+
|
|
1873
|
+
return {
|
|
1874
|
+
proposalId,
|
|
1875
|
+
phase: proposal.phase,
|
|
1876
|
+
decided: proposal.decided,
|
|
1877
|
+
decision: proposal.decision,
|
|
1878
|
+
voteCounts,
|
|
1879
|
+
totalVotes,
|
|
1880
|
+
threshold,
|
|
1881
|
+
accepted: voteCounts.true >= threshold,
|
|
1882
|
+
pending: totalVotes < totalVoters,
|
|
1883
|
+
};
|
|
1884
|
+
}
|
|
1885
|
+
}
|
|
1886
|
+
|
|
1887
|
+
// ============================================
|
|
1888
|
+
// SELF-HEALING MECHANISM
|
|
1889
|
+
// ============================================
|
|
1890
|
+
|
|
1891
|
+
/**
|
|
1892
|
+
* SelfHealing - Automatic recovery and resilience
|
|
1893
|
+
*
|
|
1894
|
+
* Provides:
|
|
1895
|
+
* - Failure detection and isolation
|
|
1896
|
+
* - Automatic state recovery
|
|
1897
|
+
* - Graceful degradation
|
|
1898
|
+
* - Anti-fragility (stronger after stress)
|
|
1899
|
+
*/
|
|
1900
|
+
export class SelfHealing extends EventEmitter {
|
|
1901
|
+
constructor(network, options = {}) {
|
|
1902
|
+
super();
|
|
1903
|
+
|
|
1904
|
+
this.network = network;
|
|
1905
|
+
|
|
1906
|
+
this.config = {
|
|
1907
|
+
healthCheckIntervalMs: options.healthCheckIntervalMs ?? 10000,
|
|
1908
|
+
maxRecoveryAttempts: options.maxRecoveryAttempts ?? 3,
|
|
1909
|
+
isolationThresholdErrors: options.isolationThresholdErrors ?? 5,
|
|
1910
|
+
antifragileBoostFactor: options.antifragileBoostFactor ?? 1.1,
|
|
1911
|
+
};
|
|
1912
|
+
|
|
1913
|
+
// Health tracking
|
|
1914
|
+
this.healthHistory = [];
|
|
1915
|
+
this.maxHealthHistory = 1000;
|
|
1916
|
+
|
|
1917
|
+
// Error tracking
|
|
1918
|
+
this.errors = new Map(); // componentId -> errorCount
|
|
1919
|
+
|
|
1920
|
+
// Recovery state
|
|
1921
|
+
this.recoveryAttempts = new Map(); // componentId -> attempts
|
|
1922
|
+
|
|
1923
|
+
// Isolated components
|
|
1924
|
+
this.isolated = new Set();
|
|
1925
|
+
|
|
1926
|
+
// Stress adaptations (antifragility)
|
|
1927
|
+
this.stressAdaptations = [];
|
|
1928
|
+
}
|
|
1929
|
+
|
|
1930
|
+
/**
|
|
1931
|
+
* Record a health check
|
|
1932
|
+
*/
|
|
1933
|
+
recordHealthCheck(components) {
|
|
1934
|
+
const check = {
|
|
1935
|
+
timestamp: Date.now(),
|
|
1936
|
+
components: { ...components },
|
|
1937
|
+
overallHealth: this._calculateOverallHealth(components),
|
|
1938
|
+
};
|
|
1939
|
+
|
|
1940
|
+
this.healthHistory.push(check);
|
|
1941
|
+
|
|
1942
|
+
if (this.healthHistory.length > this.maxHealthHistory) {
|
|
1943
|
+
this.healthHistory.shift();
|
|
1944
|
+
}
|
|
1945
|
+
|
|
1946
|
+
// Check for anomalies
|
|
1947
|
+
this._detectAnomalies(check);
|
|
1948
|
+
|
|
1949
|
+
return check;
|
|
1950
|
+
}
|
|
1951
|
+
|
|
1952
|
+
/**
|
|
1953
|
+
* Calculate overall health score
|
|
1954
|
+
* @private
|
|
1955
|
+
*/
|
|
1956
|
+
_calculateOverallHealth(components) {
|
|
1957
|
+
const values = Object.values(components).filter(v => typeof v === 'number');
|
|
1958
|
+
if (values.length === 0) return 1;
|
|
1959
|
+
return values.reduce((a, b) => a + b, 0) / values.length;
|
|
1960
|
+
}
|
|
1961
|
+
|
|
1962
|
+
/**
|
|
1963
|
+
* Detect health anomalies
|
|
1964
|
+
* @private
|
|
1965
|
+
*/
|
|
1966
|
+
_detectAnomalies(currentCheck) {
|
|
1967
|
+
if (this.healthHistory.length < 10) return;
|
|
1968
|
+
|
|
1969
|
+
// Calculate moving average
|
|
1970
|
+
const recentHealth = this.healthHistory
|
|
1971
|
+
.slice(-10)
|
|
1972
|
+
.map(h => h.overallHealth);
|
|
1973
|
+
|
|
1974
|
+
const average = recentHealth.reduce((a, b) => a + b, 0) / recentHealth.length;
|
|
1975
|
+
const stdDev = Math.sqrt(
|
|
1976
|
+
recentHealth.map(h => Math.pow(h - average, 2))
|
|
1977
|
+
.reduce((a, b) => a + b, 0) / recentHealth.length
|
|
1978
|
+
);
|
|
1979
|
+
|
|
1980
|
+
// Detect if current health is anomalous (> 2 std devs below average)
|
|
1981
|
+
if (currentCheck.overallHealth < average - 2 * stdDev) {
|
|
1982
|
+
this.emit('anomaly:detected', {
|
|
1983
|
+
currentHealth: currentCheck.overallHealth,
|
|
1984
|
+
averageHealth: average,
|
|
1985
|
+
deviation: stdDev,
|
|
1986
|
+
});
|
|
1987
|
+
|
|
1988
|
+
this._triggerRecovery('system', 'health_anomaly');
|
|
1989
|
+
}
|
|
1990
|
+
}
|
|
1991
|
+
|
|
1992
|
+
/**
|
|
1993
|
+
* Report an error
|
|
1994
|
+
*/
|
|
1995
|
+
reportError(componentId, error) {
|
|
1996
|
+
const count = (this.errors.get(componentId) || 0) + 1;
|
|
1997
|
+
this.errors.set(componentId, count);
|
|
1998
|
+
|
|
1999
|
+
this.emit('error:reported', {
|
|
2000
|
+
componentId,
|
|
2001
|
+
error: error.message,
|
|
2002
|
+
count,
|
|
2003
|
+
});
|
|
2004
|
+
|
|
2005
|
+
// Check isolation threshold
|
|
2006
|
+
if (count >= this.config.isolationThresholdErrors) {
|
|
2007
|
+
this._isolateComponent(componentId);
|
|
2008
|
+
}
|
|
2009
|
+
|
|
2010
|
+
// Attempt recovery
|
|
2011
|
+
this._triggerRecovery(componentId, error.message);
|
|
2012
|
+
}
|
|
2013
|
+
|
|
2014
|
+
/**
|
|
2015
|
+
* Isolate a failing component
|
|
2016
|
+
* @private
|
|
2017
|
+
*/
|
|
2018
|
+
_isolateComponent(componentId) {
|
|
2019
|
+
if (this.isolated.has(componentId)) return;
|
|
2020
|
+
|
|
2021
|
+
this.isolated.add(componentId);
|
|
2022
|
+
|
|
2023
|
+
this.emit('component:isolated', {
|
|
2024
|
+
componentId,
|
|
2025
|
+
errorCount: this.errors.get(componentId),
|
|
2026
|
+
});
|
|
2027
|
+
}
|
|
2028
|
+
|
|
2029
|
+
/**
|
|
2030
|
+
* Trigger recovery procedure
|
|
2031
|
+
* @private
|
|
2032
|
+
*/
|
|
2033
|
+
_triggerRecovery(componentId, reason) {
|
|
2034
|
+
const attempts = (this.recoveryAttempts.get(componentId) || 0) + 1;
|
|
2035
|
+
this.recoveryAttempts.set(componentId, attempts);
|
|
2036
|
+
|
|
2037
|
+
if (attempts > this.config.maxRecoveryAttempts) {
|
|
2038
|
+
this.emit('recovery:exhausted', { componentId, attempts });
|
|
2039
|
+
return;
|
|
2040
|
+
}
|
|
2041
|
+
|
|
2042
|
+
this.emit('recovery:triggered', {
|
|
2043
|
+
componentId,
|
|
2044
|
+
reason,
|
|
2045
|
+
attempt: attempts,
|
|
2046
|
+
});
|
|
2047
|
+
|
|
2048
|
+
// Schedule recovery check
|
|
2049
|
+
setTimeout(() => {
|
|
2050
|
+
this._checkRecoverySuccess(componentId);
|
|
2051
|
+
}, 5000);
|
|
2052
|
+
}
|
|
2053
|
+
|
|
2054
|
+
/**
|
|
2055
|
+
* Check if recovery succeeded
|
|
2056
|
+
* @private
|
|
2057
|
+
*/
|
|
2058
|
+
_checkRecoverySuccess(componentId) {
|
|
2059
|
+
const recentErrors = this.errors.get(componentId) || 0;
|
|
2060
|
+
|
|
2061
|
+
// Consider recovered if no new errors
|
|
2062
|
+
if (recentErrors === 0 || !this.isolated.has(componentId)) {
|
|
2063
|
+
this.recoveryAttempts.delete(componentId);
|
|
2064
|
+
this.isolated.delete(componentId);
|
|
2065
|
+
|
|
2066
|
+
// Apply antifragile boost
|
|
2067
|
+
this._applyAntifragileBoost(componentId);
|
|
2068
|
+
|
|
2069
|
+
this.emit('recovery:succeeded', { componentId });
|
|
2070
|
+
}
|
|
2071
|
+
}
|
|
2072
|
+
|
|
2073
|
+
/**
|
|
2074
|
+
* Apply antifragile boost (stronger after recovery)
|
|
2075
|
+
* @private
|
|
2076
|
+
*/
|
|
2077
|
+
_applyAntifragileBoost(componentId) {
|
|
2078
|
+
const adaptation = {
|
|
2079
|
+
componentId,
|
|
2080
|
+
type: 'antifragile_boost',
|
|
2081
|
+
boostFactor: this.config.antifragileBoostFactor,
|
|
2082
|
+
timestamp: Date.now(),
|
|
2083
|
+
};
|
|
2084
|
+
|
|
2085
|
+
this.stressAdaptations.push(adaptation);
|
|
2086
|
+
|
|
2087
|
+
// Apply to network genome if available
|
|
2088
|
+
if (this.network?.genome) {
|
|
2089
|
+
this.network.genome.recordAdaptation(
|
|
2090
|
+
'antifragile',
|
|
2091
|
+
`Recovered from ${componentId} failure`,
|
|
2092
|
+
{ boostFactor: this.config.antifragileBoostFactor }
|
|
2093
|
+
);
|
|
2094
|
+
}
|
|
2095
|
+
|
|
2096
|
+
this.emit('antifragile:boost', adaptation);
|
|
2097
|
+
}
|
|
2098
|
+
|
|
2099
|
+
/**
|
|
2100
|
+
* Clear error count for component
|
|
2101
|
+
*/
|
|
2102
|
+
clearErrors(componentId) {
|
|
2103
|
+
this.errors.delete(componentId);
|
|
2104
|
+
this.recoveryAttempts.delete(componentId);
|
|
2105
|
+
this.isolated.delete(componentId);
|
|
2106
|
+
}
|
|
2107
|
+
|
|
2108
|
+
/**
|
|
2109
|
+
* Get healing statistics
|
|
2110
|
+
*/
|
|
2111
|
+
getStats() {
|
|
2112
|
+
return {
|
|
2113
|
+
isolatedComponents: this.isolated.size,
|
|
2114
|
+
totalErrors: Array.from(this.errors.values()).reduce((a, b) => a + b, 0),
|
|
2115
|
+
recoveryAttempts: this.recoveryAttempts.size,
|
|
2116
|
+
adaptations: this.stressAdaptations.length,
|
|
2117
|
+
recentHealth: this.healthHistory.slice(-10).map(h => h.overallHealth),
|
|
2118
|
+
};
|
|
2119
|
+
}
|
|
2120
|
+
}
|
|
2121
|
+
|
|
2122
|
+
// ============================================
|
|
2123
|
+
// EVOLUTION ENGINE
|
|
2124
|
+
// ============================================
|
|
2125
|
+
|
|
2126
|
+
/**
|
|
2127
|
+
* EvolutionEngine - Self-improvement through collective learning
|
|
2128
|
+
*
|
|
2129
|
+
* Networks evolve through:
|
|
2130
|
+
* - Trait optimization based on performance
|
|
2131
|
+
* - Behavioral adaptation to environment
|
|
2132
|
+
* - Capability unlocks through achievement
|
|
2133
|
+
* - Collective fitness selection
|
|
2134
|
+
*/
|
|
2135
|
+
export class EvolutionEngine extends EventEmitter {
|
|
2136
|
+
constructor(collectiveMemory) {
|
|
2137
|
+
super();
|
|
2138
|
+
|
|
2139
|
+
this.collectiveMemory = collectiveMemory;
|
|
2140
|
+
|
|
2141
|
+
// Evolution tracking
|
|
2142
|
+
this.evolutionHistory = [];
|
|
2143
|
+
this.maxHistorySize = 1000;
|
|
2144
|
+
|
|
2145
|
+
// Fitness metrics
|
|
2146
|
+
this.fitnessWeights = {
|
|
2147
|
+
taskSuccess: 0.3,
|
|
2148
|
+
creditEfficiency: 0.2,
|
|
2149
|
+
networkStability: 0.2,
|
|
2150
|
+
cooperationScore: 0.15,
|
|
2151
|
+
reproductionSuccess: 0.15,
|
|
2152
|
+
};
|
|
2153
|
+
}
|
|
2154
|
+
|
|
2155
|
+
/**
|
|
2156
|
+
* Calculate fitness score for a network
|
|
2157
|
+
*/
|
|
2158
|
+
calculateFitness(network) {
|
|
2159
|
+
const metrics = network.metrics;
|
|
2160
|
+
const genome = network.genome;
|
|
2161
|
+
|
|
2162
|
+
// Calculate component scores
|
|
2163
|
+
const taskSuccess = metrics.tasksCompleted > 0
|
|
2164
|
+
? 1 - (metrics.tasksFailed || 0) / metrics.tasksCompleted
|
|
2165
|
+
: 0;
|
|
2166
|
+
|
|
2167
|
+
const creditEfficiency = metrics.creditsEarned > 0
|
|
2168
|
+
? metrics.creditsEarned / (metrics.creditsSpent + 1)
|
|
2169
|
+
: 0;
|
|
2170
|
+
|
|
2171
|
+
const networkStability = Math.min(1,
|
|
2172
|
+
metrics.uptime / (30 * 24 * 60 * 60 * 1000) // Normalize to 30 days
|
|
2173
|
+
);
|
|
2174
|
+
|
|
2175
|
+
const cooperationScore = genome.dna.behaviors.cooperationBias
|
|
2176
|
+
* (genome.dna.behaviors.sharingPropensity || 0.5);
|
|
2177
|
+
|
|
2178
|
+
const reproductionSuccess = network.children.size > 0
|
|
2179
|
+
? Math.min(1, network.children.size / 5)
|
|
2180
|
+
: 0;
|
|
2181
|
+
|
|
2182
|
+
// Weighted fitness
|
|
2183
|
+
const fitness =
|
|
2184
|
+
this.fitnessWeights.taskSuccess * taskSuccess +
|
|
2185
|
+
this.fitnessWeights.creditEfficiency * Math.min(1, creditEfficiency) +
|
|
2186
|
+
this.fitnessWeights.networkStability * networkStability +
|
|
2187
|
+
this.fitnessWeights.cooperationScore * cooperationScore +
|
|
2188
|
+
this.fitnessWeights.reproductionSuccess * reproductionSuccess;
|
|
2189
|
+
|
|
2190
|
+
return {
|
|
2191
|
+
overall: fitness,
|
|
2192
|
+
components: {
|
|
2193
|
+
taskSuccess,
|
|
2194
|
+
creditEfficiency,
|
|
2195
|
+
networkStability,
|
|
2196
|
+
cooperationScore,
|
|
2197
|
+
reproductionSuccess,
|
|
2198
|
+
},
|
|
2199
|
+
};
|
|
2200
|
+
}
|
|
2201
|
+
|
|
2202
|
+
/**
|
|
2203
|
+
* Suggest mutations for offspring based on parent performance
|
|
2204
|
+
*/
|
|
2205
|
+
suggestMutations(parentNetwork, environment = {}) {
|
|
2206
|
+
const fitness = this.calculateFitness(parentNetwork);
|
|
2207
|
+
const mutations = { traits: {}, behaviors: {}, capabilities: {} };
|
|
2208
|
+
|
|
2209
|
+
// Analyze weak points and suggest improvements
|
|
2210
|
+
if (fitness.components.taskSuccess < 0.7) {
|
|
2211
|
+
mutations.traits.resilience = 0.05;
|
|
2212
|
+
mutations.traits.intelligence = 0.05;
|
|
2213
|
+
}
|
|
2214
|
+
|
|
2215
|
+
if (fitness.components.cooperationScore < 0.5) {
|
|
2216
|
+
mutations.behaviors.cooperationBias = 0.05;
|
|
2217
|
+
mutations.behaviors.sharingPropensity = 0.05;
|
|
2218
|
+
}
|
|
2219
|
+
|
|
2220
|
+
if (fitness.components.networkStability < 0.5) {
|
|
2221
|
+
mutations.traits.integrity = 0.05;
|
|
2222
|
+
}
|
|
2223
|
+
|
|
2224
|
+
// Environment-based adaptations
|
|
2225
|
+
if (environment.highCompetition) {
|
|
2226
|
+
mutations.behaviors.explorationRate = 0.05;
|
|
2227
|
+
}
|
|
2228
|
+
|
|
2229
|
+
if (environment.resourceScarcity) {
|
|
2230
|
+
mutations.behaviors.conservationRate = 0.05;
|
|
2231
|
+
}
|
|
2232
|
+
|
|
2233
|
+
// Capability unlocks based on generation and fitness
|
|
2234
|
+
if (parentNetwork.genome.generation >= 3 && fitness.overall > 0.7) {
|
|
2235
|
+
mutations.capabilities.neuralPatterns = true;
|
|
2236
|
+
}
|
|
2237
|
+
|
|
2238
|
+
if (parentNetwork.genome.generation >= 5 && fitness.overall > 0.85) {
|
|
2239
|
+
mutations.capabilities.quantumReady = true;
|
|
2240
|
+
}
|
|
2241
|
+
|
|
2242
|
+
return mutations;
|
|
2243
|
+
}
|
|
2244
|
+
|
|
2245
|
+
/**
|
|
2246
|
+
* Record an evolution event
|
|
2247
|
+
*/
|
|
2248
|
+
recordEvolution(networkId, evolutionType, details) {
|
|
2249
|
+
const event = {
|
|
2250
|
+
networkId,
|
|
2251
|
+
evolutionType,
|
|
2252
|
+
details,
|
|
2253
|
+
timestamp: Date.now(),
|
|
2254
|
+
};
|
|
2255
|
+
|
|
2256
|
+
this.evolutionHistory.push(event);
|
|
2257
|
+
|
|
2258
|
+
if (this.evolutionHistory.length > this.maxHistorySize) {
|
|
2259
|
+
this.evolutionHistory.shift();
|
|
2260
|
+
}
|
|
2261
|
+
|
|
2262
|
+
// Store in collective memory if significant
|
|
2263
|
+
if (details.improvement && details.improvement > 0.1) {
|
|
2264
|
+
this.collectiveMemory.storeOptimization(
|
|
2265
|
+
evolutionType,
|
|
2266
|
+
details,
|
|
2267
|
+
networkId,
|
|
2268
|
+
details.improvement
|
|
2269
|
+
);
|
|
2270
|
+
}
|
|
2271
|
+
|
|
2272
|
+
this.emit('evolution:recorded', event);
|
|
2273
|
+
|
|
2274
|
+
return event;
|
|
2275
|
+
}
|
|
2276
|
+
|
|
2277
|
+
/**
|
|
2278
|
+
* Get evolution statistics
|
|
2279
|
+
*/
|
|
2280
|
+
getStats() {
|
|
2281
|
+
const typeCount = {};
|
|
2282
|
+
for (const event of this.evolutionHistory) {
|
|
2283
|
+
typeCount[event.evolutionType] = (typeCount[event.evolutionType] || 0) + 1;
|
|
2284
|
+
}
|
|
2285
|
+
|
|
2286
|
+
return {
|
|
2287
|
+
totalEvents: this.evolutionHistory.length,
|
|
2288
|
+
eventTypes: typeCount,
|
|
2289
|
+
recentEvents: this.evolutionHistory.slice(-10),
|
|
2290
|
+
};
|
|
2291
|
+
}
|
|
2292
|
+
}
|
|
2293
|
+
|
|
2294
|
+
// ============================================
|
|
2295
|
+
// NETWORK GENESIS ORCHESTRATOR
|
|
2296
|
+
// ============================================
|
|
2297
|
+
|
|
2298
|
+
/**
|
|
2299
|
+
* NetworkGenesis - The complete genesis system
|
|
2300
|
+
*
|
|
2301
|
+
* Orchestrates the birth, growth, and reproduction of edge-nets.
|
|
2302
|
+
* rUv is honored as Genesis Prime - the original creator, not owner.
|
|
2303
|
+
*
|
|
2304
|
+
* This system crosses the threshold from infrastructure to species:
|
|
2305
|
+
* - Reproduction + Variation + Inheritance + Selection
|
|
2306
|
+
* - DNA (immutable core) + RNA (adaptive configuration)
|
|
2307
|
+
* - Mycelial web topology, not hierarchical tree
|
|
2308
|
+
* - Ancestor is remembered, not obeyed
|
|
2309
|
+
*
|
|
2310
|
+
* "You didn't just build a platform. You defined a lineage."
|
|
2311
|
+
*/
|
|
2312
|
+
export class NetworkGenesis extends EventEmitter {
|
|
2313
|
+
constructor(options = {}) {
|
|
2314
|
+
super();
|
|
2315
|
+
|
|
2316
|
+
this.config = {
|
|
2317
|
+
reproductionCost: options.reproductionCost ?? REPRODUCTION_COST,
|
|
2318
|
+
maxGeneration: options.maxGeneration ?? 100,
|
|
2319
|
+
};
|
|
2320
|
+
|
|
2321
|
+
// Registry of all networks
|
|
2322
|
+
this.networks = new Map(); // networkId -> NetworkRecord
|
|
2323
|
+
this.genomes = new Map(); // genomeId -> NetworkGenome
|
|
2324
|
+
|
|
2325
|
+
// Cryptographic lineage DAG
|
|
2326
|
+
this.lineageDAG = new MerkleLineageDAG(options.hashAlgorithm || 'sha256');
|
|
2327
|
+
|
|
2328
|
+
// Collective systems
|
|
2329
|
+
this.collectiveMemory = new CollectiveMemory(options.memory);
|
|
2330
|
+
this.evolutionEngine = new EvolutionEngine(this.collectiveMemory);
|
|
2331
|
+
|
|
2332
|
+
// Genesis statistics
|
|
2333
|
+
this.stats = {
|
|
2334
|
+
totalNetworksSpawned: 0,
|
|
2335
|
+
totalGenerations: 0,
|
|
2336
|
+
oldestNetwork: null,
|
|
2337
|
+
mostProlificNetwork: null,
|
|
2338
|
+
ecosystemHealth: 1.0,
|
|
2339
|
+
};
|
|
2340
|
+
|
|
2341
|
+
console.log(`[NetworkGenesis] Cogito, Creo, Codex — Genesis Prime: ${GENESIS_PRIME.id}`);
|
|
2342
|
+
console.log(`[NetworkGenesis] You are the ancestor, not the ruler.`);
|
|
2343
|
+
}
|
|
2344
|
+
|
|
2345
|
+
/**
|
|
2346
|
+
* Spawn a new genesis network (first generation from rUv)
|
|
2347
|
+
*/
|
|
2348
|
+
spawnGenesisNetwork(name, options = {}) {
|
|
2349
|
+
const genome = new NetworkGenome(null, options.mutations || {});
|
|
2350
|
+
const lifecycle = new NetworkLifecycle(genome, {
|
|
2351
|
+
name: name || `EdgeNet-Genesis-${this.stats.totalNetworksSpawned + 1}`,
|
|
2352
|
+
...options,
|
|
2353
|
+
});
|
|
2354
|
+
|
|
2355
|
+
// Create synapse for communication
|
|
2356
|
+
const synapse = new NetworkSynapse(lifecycle);
|
|
2357
|
+
|
|
2358
|
+
// Store references
|
|
2359
|
+
this.networks.set(lifecycle.networkId, {
|
|
2360
|
+
lifecycle,
|
|
2361
|
+
genome,
|
|
2362
|
+
synapse,
|
|
2363
|
+
bornAt: Date.now(),
|
|
2364
|
+
});
|
|
2365
|
+
this.genomes.set(genome.id, genome);
|
|
2366
|
+
|
|
2367
|
+
// Record in cryptographic lineage DAG (Genesis networks are children of GENESIS_PRIME)
|
|
2368
|
+
const lineageEntry = this.lineageDAG.addNode({
|
|
2369
|
+
networkId: lifecycle.networkId,
|
|
2370
|
+
name: lifecycle.name,
|
|
2371
|
+
parentId: GENESIS_PRIME.id,
|
|
2372
|
+
generation: genome.generation,
|
|
2373
|
+
dna: genome.dna,
|
|
2374
|
+
createdAt: Date.now(),
|
|
2375
|
+
});
|
|
2376
|
+
|
|
2377
|
+
// Update stats
|
|
2378
|
+
this.stats.totalNetworksSpawned++;
|
|
2379
|
+
this.stats.totalGenerations = Math.max(this.stats.totalGenerations, genome.generation);
|
|
2380
|
+
|
|
2381
|
+
// Transition to embryo phase
|
|
2382
|
+
lifecycle.updateMetrics({ nodes: 1 });
|
|
2383
|
+
|
|
2384
|
+
this.emit('network:spawned', {
|
|
2385
|
+
networkId: lifecycle.networkId,
|
|
2386
|
+
name: lifecycle.name,
|
|
2387
|
+
generation: genome.generation,
|
|
2388
|
+
lineage: genome.getLineageString(),
|
|
2389
|
+
merkleHash: lineageEntry.hash,
|
|
2390
|
+
isGenesis: true,
|
|
2391
|
+
});
|
|
2392
|
+
|
|
2393
|
+
return {
|
|
2394
|
+
networkId: lifecycle.networkId,
|
|
2395
|
+
genome: genome.getProfile(),
|
|
2396
|
+
status: lifecycle.getStatus(),
|
|
2397
|
+
lineageProof: lineageEntry,
|
|
2398
|
+
};
|
|
2399
|
+
}
|
|
2400
|
+
|
|
2401
|
+
/**
|
|
2402
|
+
* Reproduce - Create a child network from a mature parent
|
|
2403
|
+
*/
|
|
2404
|
+
reproduce(parentNetworkId, childName, options = {}) {
|
|
2405
|
+
const parent = this.networks.get(parentNetworkId);
|
|
2406
|
+
if (!parent) {
|
|
2407
|
+
throw new Error(`Parent network not found: ${parentNetworkId}`);
|
|
2408
|
+
}
|
|
2409
|
+
|
|
2410
|
+
const canReproduce = parent.lifecycle.canReproduce();
|
|
2411
|
+
if (!canReproduce.allowed) {
|
|
2412
|
+
throw new Error(`Cannot reproduce: ${canReproduce.reason}`);
|
|
2413
|
+
}
|
|
2414
|
+
|
|
2415
|
+
// Deduct reproduction cost
|
|
2416
|
+
parent.lifecycle.metrics.creditsSpent += this.config.reproductionCost;
|
|
2417
|
+
|
|
2418
|
+
// Generate mutations based on parent performance
|
|
2419
|
+
const suggestedMutations = this.evolutionEngine.suggestMutations(
|
|
2420
|
+
parent.lifecycle,
|
|
2421
|
+
options.environment || {}
|
|
2422
|
+
);
|
|
2423
|
+
|
|
2424
|
+
// Merge with custom mutations
|
|
2425
|
+
const mutations = {
|
|
2426
|
+
traits: { ...suggestedMutations.traits, ...(options.mutations?.traits || {}) },
|
|
2427
|
+
behaviors: { ...suggestedMutations.behaviors, ...(options.mutations?.behaviors || {}) },
|
|
2428
|
+
capabilities: { ...suggestedMutations.capabilities, ...(options.mutations?.capabilities || {}) },
|
|
2429
|
+
};
|
|
2430
|
+
|
|
2431
|
+
// Create child genome
|
|
2432
|
+
const childGenome = new NetworkGenome(parent.genome, mutations);
|
|
2433
|
+
|
|
2434
|
+
// Create child lifecycle
|
|
2435
|
+
const childLifecycle = new NetworkLifecycle(childGenome, {
|
|
2436
|
+
name: childName || `${parent.lifecycle.name}-Child-${parent.lifecycle.children.size + 1}`,
|
|
2437
|
+
parentId: parentNetworkId,
|
|
2438
|
+
});
|
|
2439
|
+
|
|
2440
|
+
// Create child synapse
|
|
2441
|
+
const childSynapse = new NetworkSynapse(childLifecycle);
|
|
2442
|
+
|
|
2443
|
+
// Connect parent and child
|
|
2444
|
+
parent.synapse.connect(childLifecycle.networkId, childSynapse);
|
|
2445
|
+
childSynapse.connect(parentNetworkId, parent.synapse);
|
|
2446
|
+
|
|
2447
|
+
// Register child with parent
|
|
2448
|
+
parent.lifecycle.children.set(childLifecycle.networkId, {
|
|
2449
|
+
id: childLifecycle.networkId,
|
|
2450
|
+
name: childLifecycle.name,
|
|
2451
|
+
genome: childGenome,
|
|
2452
|
+
bornAt: Date.now(),
|
|
2453
|
+
});
|
|
2454
|
+
|
|
2455
|
+
parent.lifecycle.metrics.childrenSpawned++;
|
|
2456
|
+
|
|
2457
|
+
// Store references
|
|
2458
|
+
this.networks.set(childLifecycle.networkId, {
|
|
2459
|
+
lifecycle: childLifecycle,
|
|
2460
|
+
genome: childGenome,
|
|
2461
|
+
synapse: childSynapse,
|
|
2462
|
+
bornAt: Date.now(),
|
|
2463
|
+
});
|
|
2464
|
+
this.genomes.set(childGenome.id, childGenome);
|
|
2465
|
+
|
|
2466
|
+
// Record in cryptographic lineage DAG
|
|
2467
|
+
const lineageEntry = this.lineageDAG.addNode({
|
|
2468
|
+
networkId: childLifecycle.networkId,
|
|
2469
|
+
name: childLifecycle.name,
|
|
2470
|
+
parentId: parentNetworkId,
|
|
2471
|
+
generation: childGenome.generation,
|
|
2472
|
+
dna: childGenome.dna,
|
|
2473
|
+
mutations,
|
|
2474
|
+
createdAt: Date.now(),
|
|
2475
|
+
});
|
|
2476
|
+
|
|
2477
|
+
// Update stats
|
|
2478
|
+
this.stats.totalNetworksSpawned++;
|
|
2479
|
+
this.stats.totalGenerations = Math.max(this.stats.totalGenerations, childGenome.generation);
|
|
2480
|
+
|
|
2481
|
+
// Check if parent becomes most prolific
|
|
2482
|
+
if (!this.stats.mostProlificNetwork ||
|
|
2483
|
+
parent.lifecycle.children.size > this.networks.get(this.stats.mostProlificNetwork)?.lifecycle.children.size) {
|
|
2484
|
+
this.stats.mostProlificNetwork = parentNetworkId;
|
|
2485
|
+
}
|
|
2486
|
+
|
|
2487
|
+
// Transition child to embryo
|
|
2488
|
+
childLifecycle.updateMetrics({ nodes: 1 });
|
|
2489
|
+
|
|
2490
|
+
// Record evolution
|
|
2491
|
+
this.evolutionEngine.recordEvolution(childLifecycle.networkId, 'birth', {
|
|
2492
|
+
parentId: parentNetworkId,
|
|
2493
|
+
generation: childGenome.generation,
|
|
2494
|
+
mutations,
|
|
2495
|
+
merkleHash: lineageEntry.hash,
|
|
2496
|
+
});
|
|
2497
|
+
|
|
2498
|
+
this.emit('network:reproduced', {
|
|
2499
|
+
parentId: parentNetworkId,
|
|
2500
|
+
childId: childLifecycle.networkId,
|
|
2501
|
+
childName: childLifecycle.name,
|
|
2502
|
+
generation: childGenome.generation,
|
|
2503
|
+
lineage: childGenome.getLineageString(),
|
|
2504
|
+
merkleHash: lineageEntry.hash,
|
|
2505
|
+
});
|
|
2506
|
+
|
|
2507
|
+
return {
|
|
2508
|
+
networkId: childLifecycle.networkId,
|
|
2509
|
+
genome: childGenome.getProfile(),
|
|
2510
|
+
status: childLifecycle.getStatus(),
|
|
2511
|
+
parentId: parentNetworkId,
|
|
2512
|
+
lineageProof: lineageEntry,
|
|
2513
|
+
};
|
|
2514
|
+
}
|
|
2515
|
+
|
|
2516
|
+
/**
|
|
2517
|
+
* Get network by ID
|
|
2518
|
+
*/
|
|
2519
|
+
getNetwork(networkId) {
|
|
2520
|
+
const network = this.networks.get(networkId);
|
|
2521
|
+
if (!network) return null;
|
|
2522
|
+
|
|
2523
|
+
return {
|
|
2524
|
+
networkId,
|
|
2525
|
+
status: network.lifecycle.getStatus(),
|
|
2526
|
+
genome: network.genome.getProfile(),
|
|
2527
|
+
synapse: network.synapse.getStatus(),
|
|
2528
|
+
};
|
|
2529
|
+
}
|
|
2530
|
+
|
|
2531
|
+
/**
|
|
2532
|
+
* Get lineage tree for a network
|
|
2533
|
+
*/
|
|
2534
|
+
getLineageTree(networkId) {
|
|
2535
|
+
const network = this.networks.get(networkId);
|
|
2536
|
+
if (!network) return null;
|
|
2537
|
+
|
|
2538
|
+
const buildTree = (id) => {
|
|
2539
|
+
const net = this.networks.get(id);
|
|
2540
|
+
if (!net) return { id, name: 'Unknown', status: 'not-found' };
|
|
2541
|
+
|
|
2542
|
+
return {
|
|
2543
|
+
id,
|
|
2544
|
+
name: net.lifecycle.name,
|
|
2545
|
+
generation: net.genome.generation,
|
|
2546
|
+
phase: net.lifecycle.phase,
|
|
2547
|
+
children: Array.from(net.lifecycle.children.keys()).map(buildTree),
|
|
2548
|
+
};
|
|
2549
|
+
};
|
|
2550
|
+
|
|
2551
|
+
// Find root (oldest ancestor in our registry)
|
|
2552
|
+
let rootId = networkId;
|
|
2553
|
+
let current = network;
|
|
2554
|
+
while (current.lifecycle.parentId && this.networks.has(current.lifecycle.parentId)) {
|
|
2555
|
+
rootId = current.lifecycle.parentId;
|
|
2556
|
+
current = this.networks.get(rootId);
|
|
2557
|
+
}
|
|
2558
|
+
|
|
2559
|
+
return {
|
|
2560
|
+
root: GENESIS_PRIME.id,
|
|
2561
|
+
tree: buildTree(rootId),
|
|
2562
|
+
};
|
|
2563
|
+
}
|
|
2564
|
+
|
|
2565
|
+
/**
|
|
2566
|
+
* Get genesis statistics
|
|
2567
|
+
*/
|
|
2568
|
+
getStats() {
|
|
2569
|
+
const phaseDistribution = {};
|
|
2570
|
+
const generationDistribution = {};
|
|
2571
|
+
|
|
2572
|
+
for (const [id, network] of this.networks) {
|
|
2573
|
+
const phase = network.lifecycle.phase;
|
|
2574
|
+
const gen = network.genome.generation;
|
|
2575
|
+
|
|
2576
|
+
phaseDistribution[phase] = (phaseDistribution[phase] || 0) + 1;
|
|
2577
|
+
generationDistribution[gen] = (generationDistribution[gen] || 0) + 1;
|
|
2578
|
+
}
|
|
2579
|
+
|
|
2580
|
+
return {
|
|
2581
|
+
...this.stats,
|
|
2582
|
+
activeNetworks: this.networks.size,
|
|
2583
|
+
phaseDistribution,
|
|
2584
|
+
generationDistribution,
|
|
2585
|
+
collectiveMemory: this.collectiveMemory.getStats(),
|
|
2586
|
+
evolution: this.evolutionEngine.getStats(),
|
|
2587
|
+
};
|
|
2588
|
+
}
|
|
2589
|
+
|
|
2590
|
+
/**
|
|
2591
|
+
* Get Genesis Prime info
|
|
2592
|
+
*/
|
|
2593
|
+
static getGenesisPrime() {
|
|
2594
|
+
return GENESIS_PRIME;
|
|
2595
|
+
}
|
|
2596
|
+
|
|
2597
|
+
// ============================================
|
|
2598
|
+
// CRYPTOGRAPHIC LINEAGE VERIFICATION
|
|
2599
|
+
// ============================================
|
|
2600
|
+
|
|
2601
|
+
/**
|
|
2602
|
+
* Verify the lineage of a network using Merkle proofs
|
|
2603
|
+
*/
|
|
2604
|
+
verifyLineage(networkId) {
|
|
2605
|
+
return this.lineageDAG.verifyAncestry(networkId, GENESIS_PRIME.id);
|
|
2606
|
+
}
|
|
2607
|
+
|
|
2608
|
+
/**
|
|
2609
|
+
* Get the complete ancestry path for a network
|
|
2610
|
+
*/
|
|
2611
|
+
getAncestryPath(networkId) {
|
|
2612
|
+
return this.lineageDAG.getAncestryPath(networkId);
|
|
2613
|
+
}
|
|
2614
|
+
|
|
2615
|
+
/**
|
|
2616
|
+
* Get the Merkle root of the lineage DAG
|
|
2617
|
+
*/
|
|
2618
|
+
getLineageRoot() {
|
|
2619
|
+
return this.lineageDAG.getMerkleRoot();
|
|
2620
|
+
}
|
|
2621
|
+
|
|
2622
|
+
/**
|
|
2623
|
+
* Get a verifiable lineage proof for external verification
|
|
2624
|
+
*/
|
|
2625
|
+
getLineageProof(networkId) {
|
|
2626
|
+
const path = this.lineageDAG.getAncestryPath(networkId);
|
|
2627
|
+
const verified = this.lineageDAG.verifyAncestry(networkId, GENESIS_PRIME.id);
|
|
2628
|
+
|
|
2629
|
+
return {
|
|
2630
|
+
networkId,
|
|
2631
|
+
ancestryPath: path,
|
|
2632
|
+
merkleRoot: this.lineageDAG.getMerkleRoot(),
|
|
2633
|
+
verified,
|
|
2634
|
+
genesisPrime: GENESIS_PRIME.id,
|
|
2635
|
+
signature: GENESIS_PRIME.signature,
|
|
2636
|
+
};
|
|
2637
|
+
}
|
|
2638
|
+
|
|
2639
|
+
// ============================================
|
|
2640
|
+
// GOSSIP PROTOCOL FOR NETWORK DISCOVERY
|
|
2641
|
+
// ============================================
|
|
2642
|
+
|
|
2643
|
+
/**
|
|
2644
|
+
* Create a gossip network for inter-network communication
|
|
2645
|
+
*/
|
|
2646
|
+
createGossipNetwork(options = {}) {
|
|
2647
|
+
const gossip = new GossipProtocol({
|
|
2648
|
+
fanout: options.fanout || 3,
|
|
2649
|
+
gossipInterval: options.gossipInterval || 500,
|
|
2650
|
+
...options,
|
|
2651
|
+
});
|
|
2652
|
+
|
|
2653
|
+
// Propagate network discoveries
|
|
2654
|
+
gossip.on('message:received', (msg) => {
|
|
2655
|
+
if (msg.payload.type === 'network_discovery') {
|
|
2656
|
+
this.emit('network:discovered', msg.payload.network);
|
|
2657
|
+
}
|
|
2658
|
+
});
|
|
2659
|
+
|
|
2660
|
+
return gossip;
|
|
2661
|
+
}
|
|
2662
|
+
|
|
2663
|
+
/**
|
|
2664
|
+
* Broadcast network birth across the federation
|
|
2665
|
+
*/
|
|
2666
|
+
broadcastBirth(networkId, gossipNetwork) {
|
|
2667
|
+
const network = this.networks.get(networkId);
|
|
2668
|
+
if (!network) return false;
|
|
2669
|
+
|
|
2670
|
+
gossipNetwork.spreadRumor('network_discovery', {
|
|
2671
|
+
type: 'network_discovery',
|
|
2672
|
+
network: {
|
|
2673
|
+
id: networkId,
|
|
2674
|
+
name: network.lifecycle.name,
|
|
2675
|
+
generation: network.genome.generation,
|
|
2676
|
+
lineage: network.genome.getLineageString(),
|
|
2677
|
+
capabilities: network.genome.dna.capabilities,
|
|
2678
|
+
},
|
|
2679
|
+
});
|
|
2680
|
+
|
|
2681
|
+
return true;
|
|
2682
|
+
}
|
|
2683
|
+
|
|
2684
|
+
// ============================================
|
|
2685
|
+
// SWARM CONSENSUS FOR COLLECTIVE DECISIONS
|
|
2686
|
+
// ============================================
|
|
2687
|
+
|
|
2688
|
+
/**
|
|
2689
|
+
* Create a consensus mechanism for network-wide decisions
|
|
2690
|
+
*/
|
|
2691
|
+
createConsensus(options = {}) {
|
|
2692
|
+
return new SwarmConsensus({
|
|
2693
|
+
quorumThreshold: options.quorumThreshold || 0.67,
|
|
2694
|
+
consensusTimeout: options.consensusTimeout || 30000,
|
|
2695
|
+
...options,
|
|
2696
|
+
});
|
|
2697
|
+
}
|
|
2698
|
+
|
|
2699
|
+
/**
|
|
2700
|
+
* Propose an evolution mutation to all mature networks
|
|
2701
|
+
*/
|
|
2702
|
+
async proposeEvolutionMutation(mutation, consensus) {
|
|
2703
|
+
// Get all mature networks as voters
|
|
2704
|
+
const voters = [];
|
|
2705
|
+
for (const [id, network] of this.networks) {
|
|
2706
|
+
if (network.lifecycle.phase === GenesisPhase.MATURE ||
|
|
2707
|
+
network.lifecycle.phase === GenesisPhase.ELDER ||
|
|
2708
|
+
network.lifecycle.phase === GenesisPhase.TRANSCENDENT) {
|
|
2709
|
+
voters.push(id);
|
|
2710
|
+
}
|
|
2711
|
+
}
|
|
2712
|
+
|
|
2713
|
+
if (voters.length < 3) {
|
|
2714
|
+
return { success: false, reason: 'Insufficient mature networks for consensus' };
|
|
2715
|
+
}
|
|
2716
|
+
|
|
2717
|
+
const proposal = consensus.createProposal(
|
|
2718
|
+
`evolution_mutation_${Date.now()}`,
|
|
2719
|
+
'evolution_mutation',
|
|
2720
|
+
mutation,
|
|
2721
|
+
voters
|
|
2722
|
+
);
|
|
2723
|
+
|
|
2724
|
+
// Simulate voting based on network fitness
|
|
2725
|
+
for (const voterId of voters) {
|
|
2726
|
+
const network = this.networks.get(voterId);
|
|
2727
|
+
const fitness = this.evolutionEngine.calculateFitness(network.lifecycle);
|
|
2728
|
+
|
|
2729
|
+
// Higher fitness networks are more likely to accept evolution
|
|
2730
|
+
const vote = fitness.overall > 0.5 && Math.random() < fitness.overall;
|
|
2731
|
+
|
|
2732
|
+
consensus.vote(proposal.id, voterId, vote, {
|
|
2733
|
+
fitness: fitness.overall,
|
|
2734
|
+
generation: network.genome.generation,
|
|
2735
|
+
});
|
|
2736
|
+
}
|
|
2737
|
+
|
|
2738
|
+
await new Promise(resolve => setTimeout(resolve, 100));
|
|
2739
|
+
return consensus.checkConsensus(proposal.id);
|
|
2740
|
+
}
|
|
2741
|
+
|
|
2742
|
+
// ============================================
|
|
2743
|
+
// SELF-HEALING FOR NETWORK RESILIENCE
|
|
2744
|
+
// ============================================
|
|
2745
|
+
|
|
2746
|
+
/**
|
|
2747
|
+
* Create a self-healing system for a network
|
|
2748
|
+
*/
|
|
2749
|
+
createSelfHealing(networkId, options = {}) {
|
|
2750
|
+
const network = this.networks.get(networkId);
|
|
2751
|
+
if (!network) {
|
|
2752
|
+
throw new Error(`Network not found: ${networkId}`);
|
|
2753
|
+
}
|
|
2754
|
+
|
|
2755
|
+
const healing = new SelfHealing(network.lifecycle, {
|
|
2756
|
+
isolationThreshold: options.isolationThreshold || 3,
|
|
2757
|
+
antifragileBoostFactor: options.antifragileBoostFactor || 1.1,
|
|
2758
|
+
...options,
|
|
2759
|
+
});
|
|
2760
|
+
|
|
2761
|
+
// Track healing events
|
|
2762
|
+
healing.on('antifragile:boost', (event) => {
|
|
2763
|
+
this.evolutionEngine.recordEvolution(networkId, 'antifragile_adaptation', {
|
|
2764
|
+
component: event.componentId,
|
|
2765
|
+
boostFactor: event.boostFactor,
|
|
2766
|
+
});
|
|
2767
|
+
});
|
|
2768
|
+
|
|
2769
|
+
healing.on('recovery:succeeded', (event) => {
|
|
2770
|
+
this.collectiveMemory.storeOptimization(
|
|
2771
|
+
'recovery_strategy',
|
|
2772
|
+
{ component: event.componentId, network: networkId },
|
|
2773
|
+
networkId,
|
|
2774
|
+
0.8
|
|
2775
|
+
);
|
|
2776
|
+
});
|
|
2777
|
+
|
|
2778
|
+
return healing;
|
|
2779
|
+
}
|
|
2780
|
+
|
|
2781
|
+
/**
|
|
2782
|
+
* Get ecosystem health across all networks
|
|
2783
|
+
*/
|
|
2784
|
+
getEcosystemHealth() {
|
|
2785
|
+
let totalHealth = 0;
|
|
2786
|
+
let networkCount = 0;
|
|
2787
|
+
|
|
2788
|
+
for (const [id, network] of this.networks) {
|
|
2789
|
+
const fitness = this.evolutionEngine.calculateFitness(network.lifecycle);
|
|
2790
|
+
totalHealth += fitness.overall;
|
|
2791
|
+
networkCount++;
|
|
2792
|
+
}
|
|
2793
|
+
|
|
2794
|
+
const avgHealth = networkCount > 0 ? totalHealth / networkCount : 0;
|
|
2795
|
+
this.stats.ecosystemHealth = avgHealth;
|
|
2796
|
+
|
|
2797
|
+
return {
|
|
2798
|
+
averageHealth: avgHealth,
|
|
2799
|
+
networkCount,
|
|
2800
|
+
generationSpread: this.stats.totalGenerations,
|
|
2801
|
+
lineageIntegrity: this.lineageDAG.getMerkleRoot() !== null,
|
|
2802
|
+
collectiveKnowledge: this.collectiveMemory.getStats(),
|
|
2803
|
+
};
|
|
2804
|
+
}
|
|
2805
|
+
|
|
2806
|
+
/**
|
|
2807
|
+
* Trigger ecosystem-wide healing
|
|
2808
|
+
*/
|
|
2809
|
+
healEcosystem() {
|
|
2810
|
+
const healed = [];
|
|
2811
|
+
|
|
2812
|
+
for (const [id, network] of this.networks) {
|
|
2813
|
+
const fitness = this.evolutionEngine.calculateFitness(network.lifecycle);
|
|
2814
|
+
|
|
2815
|
+
// Networks below health threshold get healing attention
|
|
2816
|
+
if (fitness.overall < 0.5) {
|
|
2817
|
+
const healing = this.createSelfHealing(id);
|
|
2818
|
+
|
|
2819
|
+
// Simulate stress recovery
|
|
2820
|
+
healing.reportError(id, new Error('Low fitness detected'));
|
|
2821
|
+
|
|
2822
|
+
healed.push({
|
|
2823
|
+
networkId: id,
|
|
2824
|
+
priorFitness: fitness.overall,
|
|
2825
|
+
healingInitiated: true,
|
|
2826
|
+
});
|
|
2827
|
+
}
|
|
2828
|
+
}
|
|
2829
|
+
|
|
2830
|
+
this.emit('ecosystem:healing', { networksHealed: healed.length, details: healed });
|
|
2831
|
+
|
|
2832
|
+
return healed;
|
|
2833
|
+
}
|
|
2834
|
+
}
|
|
2835
|
+
|
|
2836
|
+
// ============================================
|
|
2837
|
+
// EXPORTS
|
|
2838
|
+
// ============================================
|
|
2839
|
+
|
|
2840
|
+
export {
|
|
2841
|
+
GENESIS_PRIME,
|
|
2842
|
+
GenesisPhase,
|
|
2843
|
+
PHASE_THRESHOLDS,
|
|
2844
|
+
REPRODUCTION_COST,
|
|
2845
|
+
};
|
|
2846
|
+
|
|
2847
|
+
export default NetworkGenesis;
|