Merge commit 'd803bfe2b1fe7f5e219e50ac20d6801a0a58ac75' as 'vendor/ruvector'

This commit is contained in:
ruv
2026-02-28 14:39:40 -05:00
7854 changed files with 3522914 additions and 0 deletions

View File

@@ -0,0 +1,205 @@
/**
* Cell (Node) Simulation
* Represents a single node in the edge-net network
*/
import { v4 as uuidv4 } from 'uuid';
export enum CellType {
GENESIS = 'genesis',
REGULAR = 'regular',
}
export enum CellState {
ACTIVE = 'active',
READ_ONLY = 'read_only',
RETIRED = 'retired',
}
export interface CellCapabilities {
computePower: number; // 0.1 - 1.0 (relative)
bandwidth: number; // 0.1 - 1.0 (relative)
reliability: number; // 0.5 - 1.0 (uptime probability)
storage: number; // 0.1 - 1.0 (relative)
}
export interface CellMetrics {
tasksCompleted: number;
energyEarned: number;
energySpent: number;
connections: number;
uptime: number; // ticks alive
successRate: number; // task success rate
}
export class Cell {
public readonly id: string;
public readonly type: CellType;
public readonly joinedAtTick: number;
public state: CellState;
public capabilities: CellCapabilities;
public energy: number; // rUv balance
public metrics: CellMetrics;
public connectedCells: Set<string>;
public genesisMultiplier: number; // 10x for genesis nodes initially
constructor(
type: CellType,
joinedAtTick: number,
capabilities?: Partial<CellCapabilities>
) {
this.id = uuidv4();
this.type = type;
this.joinedAtTick = joinedAtTick;
this.state = CellState.ACTIVE;
this.energy = type === CellType.GENESIS ? 1000 : 10; // Genesis starts with more
this.connectedCells = new Set();
this.genesisMultiplier = type === CellType.GENESIS ? 10 : 1;
// Random capabilities or provided ones
this.capabilities = {
computePower: capabilities?.computePower ?? this.randomCapability(0.1, 1.0),
bandwidth: capabilities?.bandwidth ?? this.randomCapability(0.1, 1.0),
reliability: capabilities?.reliability ?? this.randomCapability(0.5, 1.0),
storage: capabilities?.storage ?? this.randomCapability(0.1, 1.0),
};
this.metrics = {
tasksCompleted: 0,
energyEarned: 0,
energySpent: 0,
connections: 0,
uptime: 0,
successRate: 1.0,
};
}
private randomCapability(min: number, max: number): number {
return Math.random() * (max - min) + min;
}
/**
* Process a task and earn energy
*/
public processTask(taskComplexity: number, baseReward: number): boolean {
// Check if cell is alive (reliability check)
if (Math.random() > this.capabilities.reliability) {
return false; // Cell failed this tick
}
// Check if cell has enough compute power
if (this.capabilities.computePower < taskComplexity * 0.5) {
return false; // Task too complex
}
// Success - earn energy with genesis multiplier
const reward = baseReward * this.genesisMultiplier;
this.energy += reward;
this.metrics.energyEarned += reward;
this.metrics.tasksCompleted++;
// Update success rate
this.updateSuccessRate(true);
return true;
}
/**
* Spend energy (for network operations, connections, etc.)
*/
public spendEnergy(amount: number): boolean {
if (this.energy >= amount) {
this.energy -= amount;
this.metrics.energySpent += amount;
return true;
}
return false;
}
/**
* Connect to another cell
*/
public connectTo(cellId: string): void {
if (!this.connectedCells.has(cellId)) {
this.connectedCells.add(cellId);
this.metrics.connections = this.connectedCells.size;
}
}
/**
* Disconnect from a cell
*/
public disconnectFrom(cellId: string): void {
this.connectedCells.delete(cellId);
this.metrics.connections = this.connectedCells.size;
}
/**
* Update cell state based on network phase
*/
public updateState(networkSize: number): void {
if (this.type === CellType.GENESIS) {
if (networkSize >= 50000) {
// Phase 3: Maturation - Genesis goes read-only
this.state = CellState.READ_ONLY;
this.genesisMultiplier = 1; // No more bonus
} else if (networkSize >= 10000) {
// Phase 2: Growth - Genesis reduces multiplier
this.genesisMultiplier = Math.max(1, 10 * (1 - (networkSize - 10000) / 40000));
}
if (networkSize >= 100000) {
// Phase 4: Independence - Genesis retires
this.state = CellState.RETIRED;
}
}
}
/**
* Simulate one tick of operation
*/
public tick(): void {
this.metrics.uptime++;
// Passive energy decay (network costs)
const decayCost = 0.1 * this.connectedCells.size;
this.spendEnergy(decayCost);
}
/**
* Update success rate with exponential moving average
*/
private updateSuccessRate(success: boolean): void {
const alpha = 0.1; // Smoothing factor
this.metrics.successRate = alpha * (success ? 1 : 0) + (1 - alpha) * this.metrics.successRate;
}
/**
* Get cell's overall fitness score
*/
public getFitnessScore(): number {
const { computePower, bandwidth, reliability, storage } = this.capabilities;
return (computePower * 0.3 + bandwidth * 0.2 + reliability * 0.3 + storage * 0.2);
}
/**
* Serialize cell state for reporting
*/
public toJSON() {
return {
id: this.id,
type: this.type,
state: this.state,
joinedAtTick: this.joinedAtTick,
energy: this.energy,
genesisMultiplier: this.genesisMultiplier,
capabilities: this.capabilities,
metrics: {
...this.metrics,
netEnergy: this.metrics.energyEarned - this.metrics.energySpent,
},
connections: this.connectedCells.size,
fitnessScore: this.getFitnessScore(),
};
}
}

View File

@@ -0,0 +1,190 @@
/**
* Economic Tracking and Analysis
* Monitors economic health, sustainability, and distribution
*/
export class EconomicTracker {
constructor() {
this.totalSupply = 0;
this.treasury = 0;
this.contributorPool = 0;
this.protocolFund = 0;
this.founderPool = 0;
// Distribution ratios
this.distribution = {
contributors: 0.70,
treasury: 0.15,
protocol: 0.10,
founders: 0.05,
};
// Health metrics
this.velocity = 0;
this.utilization = 0;
this.growthRate = 0;
this.stability = 1.0;
// Historical data
this.history = [];
this.epochCount = 0;
}
/**
* Process a simulation tick
*/
tick(nodes, metrics) {
// Calculate new rUv minted this tick
const totalEarned = nodes.reduce((sum, n) => sum + n.ruvEarned, 0);
const totalSpent = nodes.reduce((sum, n) => sum + n.ruvSpent, 0);
const newSupply = totalEarned - this.totalSupply;
this.totalSupply = totalEarned;
if (newSupply > 0) {
// Distribute according to ratios
this.contributorPool += Math.floor(newSupply * this.distribution.contributors);
this.treasury += Math.floor(newSupply * this.distribution.treasury);
this.protocolFund += Math.floor(newSupply * this.distribution.protocol);
this.founderPool += Math.floor(newSupply * this.distribution.founders);
}
// Update health metrics
this.updateHealthMetrics(nodes, metrics, totalSpent);
// Record snapshot periodically
if (this.epochCount % 10 === 0) {
this.recordSnapshot(nodes.length, metrics);
}
this.epochCount++;
}
/**
* Update economic health metrics
*/
updateHealthMetrics(nodes, metrics, totalSpent) {
// Velocity: how fast rUv circulates (spent / supply)
this.velocity = this.totalSupply > 0
? totalSpent / this.totalSupply
: 0;
// Utilization: active nodes / total supply capacity
const activeNodes = nodes.filter(n => n.active).length;
this.utilization = activeNodes > 0
? Math.min(1.0, metrics.totalTasksCompleted / (activeNodes * 100))
: 0;
// Growth rate: change in supply (simplified)
this.growthRate = this.totalSupply > 0
? 0.01 // Simplified constant growth
: 0;
// Stability: balance across pools
this.stability = this.calculateStability();
}
/**
* Calculate stability index based on pool distribution
*/
calculateStability() {
const totalPools = this.treasury + this.contributorPool + this.protocolFund;
if (totalPools === 0) return 1.0;
const treasuryRatio = this.treasury / totalPools;
const contributorRatio = this.contributorPool / totalPools;
const protocolRatio = this.protocolFund / totalPools;
// Ideal is 33% each
const ideal = 0.33;
const variance = Math.pow(treasuryRatio - ideal, 2) +
Math.pow(contributorRatio - ideal, 2) +
Math.pow(protocolRatio - ideal, 2);
return Math.max(0, Math.min(1.0, 1.0 - Math.sqrt(variance)));
}
/**
* Check if network is economically self-sustaining
*/
isSelfSustaining(activeNodes, dailyTasks) {
const minNodes = 100;
const minDailyTasks = 1000;
const treasuryRunwayDays = 90;
const estimatedDailyCost = activeNodes * 10; // 10 rUv per node per day
return (
activeNodes >= minNodes &&
dailyTasks >= minDailyTasks &&
this.treasury >= estimatedDailyCost * treasuryRunwayDays &&
this.growthRate >= 0.0
);
}
/**
* Get economic velocity (transactions per period)
*/
getVelocity() {
return this.velocity;
}
/**
* Record economic snapshot
*/
recordSnapshot(nodeCount, metrics) {
this.history.push({
epoch: this.epochCount,
timestamp: Date.now(),
totalSupply: this.totalSupply,
treasury: this.treasury,
contributorPool: this.contributorPool,
protocolFund: this.protocolFund,
founderPool: this.founderPool,
velocity: this.velocity,
utilization: this.utilization,
growthRate: this.growthRate,
stability: this.stability,
nodeCount,
health: this.getHealthScore(),
});
}
/**
* Get overall economic health score (0-1)
*/
getHealthScore() {
// Weighted combination of metrics
return (
this.velocity * 0.3 +
this.utilization * 0.3 +
this.stability * 0.4
);
}
/**
* Generate economic report
*/
getReport() {
return {
supply: {
total: this.totalSupply,
treasury: this.treasury,
contributors: this.contributorPool,
protocol: this.protocolFund,
founders: this.founderPool,
},
health: {
velocity: this.velocity,
utilization: this.utilization,
growthRate: this.growthRate,
stability: this.stability,
overall: this.getHealthScore(),
},
sustainability: {
selfSustaining: this.isSelfSustaining(1000, 10000), // Example values
treasuryRunway: Math.floor(this.treasury / 100), // Days
},
history: this.history,
};
}
}

View File

@@ -0,0 +1,290 @@
/**
* Metrics Collection and Aggregation
* Tracks network performance across all phases
*/
import { Network, NetworkPhase } from './network.js';
export interface PhaseMetrics {
phase: NetworkPhase;
startTick: number;
endTick: number;
duration: number;
nodeCount: {
start: number;
end: number;
peak: number;
};
energy: {
totalEarned: number;
totalSpent: number;
netEnergy: number;
avgPerNode: number;
sustainability: number; // earned / spent ratio
};
genesis: {
avgMultiplier: number;
activeCount: number;
readOnlyCount: number;
retiredCount: number;
};
network: {
avgConnections: number;
avgSuccessRate: number;
taskThroughput: number;
tasksCompleted: number;
};
validation: {
passed: boolean;
reasons: string[];
};
}
export class MetricsCollector {
private network: Network;
private phaseMetrics: Map<NetworkPhase, PhaseMetrics>;
private currentPhaseStart: number;
private currentPhaseNodeCount: number;
private peakNodeCount: number;
constructor(network: Network) {
this.network = network;
this.phaseMetrics = new Map();
this.currentPhaseStart = 0;
this.currentPhaseNodeCount = 0;
this.peakNodeCount = 0;
}
/**
* Initialize metrics collection
*/
public initialize(): void {
this.currentPhaseStart = this.network.currentTick;
this.currentPhaseNodeCount = this.network.cells.size;
this.peakNodeCount = this.network.cells.size;
}
/**
* Collect metrics for the current tick
*/
public collect(): void {
const stats = this.network.getStats();
// Update peak node count
this.peakNodeCount = Math.max(this.peakNodeCount, stats.nodeCount);
}
/**
* Handle phase transition
*/
public onPhaseTransition(oldPhase: NetworkPhase, newPhase: NetworkPhase): void {
// Finalize metrics for old phase
this.finalizePhase(oldPhase);
// Start tracking new phase
this.currentPhaseStart = this.network.currentTick;
this.currentPhaseNodeCount = this.network.cells.size;
this.peakNodeCount = this.network.cells.size;
}
/**
* Finalize metrics for a completed phase
*/
private finalizePhase(phase: NetworkPhase): void {
const stats = this.network.getStats();
const endTick = this.network.currentTick;
const duration = endTick - this.currentPhaseStart;
const cells = Array.from(this.network.cells.values());
const totalEarned = cells.reduce((sum, c) => sum + c.metrics.energyEarned, 0);
const totalSpent = cells.reduce((sum, c) => sum + c.metrics.energySpent, 0);
const totalTasks = cells.reduce((sum, c) => sum + c.metrics.tasksCompleted, 0);
const metrics: PhaseMetrics = {
phase,
startTick: this.currentPhaseStart,
endTick,
duration,
nodeCount: {
start: this.currentPhaseNodeCount,
end: stats.nodeCount,
peak: this.peakNodeCount,
},
energy: {
totalEarned,
totalSpent,
netEnergy: totalEarned - totalSpent,
avgPerNode: stats.economy.avgEnergyPerNode,
sustainability: totalSpent > 0 ? totalEarned / totalSpent : 0,
},
genesis: {
avgMultiplier: stats.genesisNodes.avgMultiplier,
activeCount: stats.genesisNodes.active,
readOnlyCount: stats.genesisNodes.readOnly,
retiredCount: stats.genesisNodes.retired,
},
network: {
avgConnections: stats.network.avgConnections,
avgSuccessRate: stats.network.avgSuccessRate,
taskThroughput: duration > 0 ? totalTasks / duration : 0,
tasksCompleted: totalTasks,
},
validation: this.validatePhase(phase, stats),
};
this.phaseMetrics.set(phase, metrics);
}
/**
* Validate phase completion criteria
*/
private validatePhase(phase: NetworkPhase, stats: any): { passed: boolean; reasons: string[] } {
const reasons: string[] = [];
let passed = true;
switch (phase) {
case NetworkPhase.GENESIS:
// Verify 10x multiplier is active
if (stats.genesisNodes.avgMultiplier < 9.0) {
passed = false;
reasons.push(`Genesis multiplier too low: ${stats.genesisNodes.avgMultiplier.toFixed(2)} (expected ~10.0)`);
} else {
reasons.push(`✓ Genesis multiplier active: ${stats.genesisNodes.avgMultiplier.toFixed(2)}x`);
}
// Verify energy accumulation
if (stats.economy.totalEarned < 1000) {
passed = false;
reasons.push(`Insufficient energy accumulation: ${stats.economy.totalEarned.toFixed(2)}`);
} else {
reasons.push(`✓ Energy accumulated: ${stats.economy.totalEarned.toFixed(2)} rUv`);
}
// Verify network formation
if (stats.network.avgConnections < 5) {
passed = false;
reasons.push(`Network poorly connected: ${stats.network.avgConnections.toFixed(2)} avg connections`);
} else {
reasons.push(`✓ Network connected: ${stats.network.avgConnections.toFixed(2)} avg connections`);
}
break;
case NetworkPhase.GROWTH:
// Verify genesis nodes stop accepting connections
if (stats.genesisNodes.active > stats.genesisNodes.count * 0.1) {
passed = false;
reasons.push(`Too many genesis nodes still active: ${stats.genesisNodes.active}`);
} else {
reasons.push(`✓ Genesis nodes reducing activity: ${stats.genesisNodes.active} active`);
}
// Verify multiplier decay
if (stats.genesisNodes.avgMultiplier > 5.0) {
passed = false;
reasons.push(`Genesis multiplier decay insufficient: ${stats.genesisNodes.avgMultiplier.toFixed(2)}`);
} else {
reasons.push(`✓ Multiplier decaying: ${stats.genesisNodes.avgMultiplier.toFixed(2)}x`);
}
// Verify task routing optimization
if (stats.network.avgSuccessRate < 0.7) {
passed = false;
reasons.push(`Task success rate too low: ${(stats.network.avgSuccessRate * 100).toFixed(1)}%`);
} else {
reasons.push(`✓ Task routing optimized: ${(stats.network.avgSuccessRate * 100).toFixed(1)}% success`);
}
break;
case NetworkPhase.MATURATION:
// Verify genesis nodes are read-only
if (stats.genesisNodes.readOnly < stats.genesisNodes.count * 0.8) {
passed = false;
reasons.push(`Genesis nodes not read-only: ${stats.genesisNodes.readOnly}/${stats.genesisNodes.count}`);
} else {
reasons.push(`✓ Genesis nodes read-only: ${stats.genesisNodes.readOnly}/${stats.genesisNodes.count}`);
}
// Verify economic sustainability
const sustainability = stats.economy.totalEarned / Math.max(stats.economy.totalSpent, 1);
if (sustainability < 1.0) {
passed = false;
reasons.push(`Network not sustainable: ${sustainability.toFixed(2)} earned/spent ratio`);
} else {
reasons.push(`✓ Economically sustainable: ${sustainability.toFixed(2)} ratio`);
}
// Verify network independence
if (stats.network.avgConnections < 10) {
passed = false;
reasons.push(`Network connectivity too low for independence: ${stats.network.avgConnections.toFixed(2)}`);
} else {
reasons.push(`✓ Network ready for independence: ${stats.network.avgConnections.toFixed(2)} avg connections`);
}
break;
case NetworkPhase.INDEPENDENCE:
// Verify genesis nodes retired
if (stats.genesisNodes.retired < stats.genesisNodes.count * 0.9) {
passed = false;
reasons.push(`Genesis nodes not fully retired: ${stats.genesisNodes.retired}/${stats.genesisNodes.count}`);
} else {
reasons.push(`✓ Genesis nodes retired: ${stats.genesisNodes.retired}/${stats.genesisNodes.count}`);
}
// Verify pure P2P operation
if (stats.genesisNodes.avgMultiplier > 1.1) {
passed = false;
reasons.push(`Genesis multiplier still active: ${stats.genesisNodes.avgMultiplier.toFixed(2)}`);
} else {
reasons.push(`✓ Pure P2P operation: ${stats.genesisNodes.avgMultiplier.toFixed(2)}x multiplier`);
}
// Verify long-term stability
if (stats.economy.netEnergy < 0) {
passed = false;
reasons.push(`Network losing energy: ${stats.economy.netEnergy.toFixed(2)}`);
} else {
reasons.push(`✓ Network stable: +${stats.economy.netEnergy.toFixed(2)} rUv net energy`);
}
break;
}
return { passed, reasons };
}
/**
* Finalize current phase (for end of simulation)
*/
public finalizeCurrent(): void {
this.finalizePhase(this.network.currentPhase);
}
/**
* Get all collected metrics
*/
public getAllMetrics(): PhaseMetrics[] {
return Array.from(this.phaseMetrics.values());
}
/**
* Get metrics for a specific phase
*/
public getPhaseMetrics(phase: NetworkPhase): PhaseMetrics | undefined {
return this.phaseMetrics.get(phase);
}
/**
* Get overall success rate
*/
public getOverallSuccess(): { passed: boolean; totalPassed: number; totalPhases: number } {
const metrics = this.getAllMetrics();
const totalPassed = metrics.filter(m => m.validation.passed).length;
const totalPhases = metrics.length;
return {
passed: totalPassed === totalPhases,
totalPassed,
totalPhases,
};
}
}

View File

@@ -0,0 +1,394 @@
/**
* Network Simulation Engine
* Manages the overall network state and lifecycle phases
*/
import { SimNode } from './node.js';
import { EconomicTracker } from './economics.js';
import { PhaseManager } from './phases.js';
export class NetworkSimulation {
constructor(config = {}) {
this.config = {
genesisNodes: config.genesisNodes || 10,
targetNodes: config.targetNodes || 100000,
tickInterval: config.tickInterval || 1000, // ms
accelerationFactor: config.accelerationFactor || 1000, // Simulate faster
...config
};
this.nodes = new Map();
this.currentTick = 0;
this.startTime = Date.now();
this.totalComputeHours = 0;
this.economics = new EconomicTracker();
this.phases = new PhaseManager();
this.metrics = {
totalTasksCompleted: 0,
totalTasksSubmitted: 0,
totalRuvCirculating: 0,
networkHealth: 1.0,
averageLatency: 0,
averageSuccessRate: 0,
};
this.events = [];
this.phaseTransitions = [];
}
/**
* Initialize the network with genesis nodes
*/
async initialize() {
console.log(`🌱 Initializing network with ${this.config.genesisNodes} genesis nodes...`);
const now = Date.now();
// Create genesis nodes
for (let i = 0; i < this.config.genesisNodes; i++) {
const node = new SimNode(`genesis-${i}`, now, true);
this.nodes.set(node.id, node);
}
// Connect genesis nodes to each other
const genesisNodes = Array.from(this.nodes.values());
for (let i = 0; i < genesisNodes.length; i++) {
for (let j = i + 1; j < genesisNodes.length; j++) {
genesisNodes[i].connectTo(genesisNodes[j].id);
genesisNodes[j].connectTo(genesisNodes[i].id);
}
}
this.logEvent('network_initialized', {
genesisNodes: this.config.genesisNodes,
timestamp: now
});
return this;
}
/**
* Run simulation for a specific phase or all phases
*/
async run(targetPhase = 'all') {
console.log(`🚀 Starting simulation (target: ${targetPhase})...`);
const phaseTargets = {
genesis: 10000,
transition: 50000,
maturity: 100000,
'post-genesis': 150000,
all: this.config.targetNodes
};
const targetNodeCount = phaseTargets[targetPhase] || this.config.targetNodes;
while (this.nodes.size < targetNodeCount) {
await this.tick();
// Add new nodes at varying rates based on phase
const currentPhase = this.getCurrentPhase();
const joinRate = this.getNodeJoinRate(currentPhase);
if (Math.random() < joinRate) {
this.addNode();
}
// Some nodes leave (churn)
if (Math.random() < 0.001 && this.nodes.size > this.config.genesisNodes) {
this.removeRandomNode();
}
// Log progress periodically
if (this.currentTick % 100 === 0) {
this.logProgress();
}
// Check for phase transitions
this.checkPhaseTransition();
}
console.log('✅ Simulation complete!');
return this.generateReport();
}
/**
* Execute a single simulation tick
*/
async tick() {
this.currentTick++;
// Accelerated time delta (ms)
const deltaTime = this.config.tickInterval * this.config.accelerationFactor;
// Update all active nodes
const currentPhase = this.getCurrentPhase();
let totalCompute = 0;
for (const node of this.nodes.values()) {
node.tick(deltaTime, this.totalComputeHours, currentPhase);
totalCompute += node.totalComputeHours;
}
this.totalComputeHours = totalCompute;
// Update network metrics
this.updateMetrics();
// Update economic state
this.economics.tick(this.getActiveNodes(), this.metrics);
// Small delay for visualization (optional)
if (this.config.visualDelay) {
await new Promise(resolve => setTimeout(resolve, this.config.visualDelay));
}
}
/**
* Add a new node to the network
*/
addNode() {
const nodeId = `node-${this.nodes.size}`;
const node = new SimNode(nodeId, Date.now(), false);
this.nodes.set(nodeId, node);
// Connect to random existing nodes
const existingNodes = Array.from(this.nodes.values())
.filter(n => n.id !== nodeId && n.canAcceptConnections());
const connectionsToMake = Math.min(5, existingNodes.length);
for (let i = 0; i < connectionsToMake; i++) {
const randomNode = existingNodes[Math.floor(Math.random() * existingNodes.length)];
node.connectTo(randomNode.id);
randomNode.connectTo(nodeId);
}
// Prefer connecting to genesis nodes initially
const currentPhase = this.getCurrentPhase();
if (currentPhase === 'genesis') {
const genesisNodes = existingNodes.filter(n => n.isGenesis && n.canAcceptConnections());
for (const gNode of genesisNodes.slice(0, 3)) {
node.connectTo(gNode.id);
gNode.connectTo(nodeId);
}
}
return node;
}
/**
* Remove a random non-genesis node (network churn)
*/
removeRandomNode() {
const regularNodes = Array.from(this.nodes.values()).filter(n => !n.isGenesis);
if (regularNodes.length === 0) return;
const nodeToRemove = regularNodes[Math.floor(Math.random() * regularNodes.length)];
// Disconnect from all peers
for (const node of this.nodes.values()) {
node.disconnect(nodeToRemove.id);
}
this.nodes.delete(nodeToRemove.id);
}
/**
* Get current network phase based on node count
*/
getCurrentPhase() {
const count = this.nodes.size;
if (count < 10000) return 'genesis';
if (count < 50000) return 'transition';
if (count < 100000) return 'maturity';
return 'post-genesis';
}
/**
* Get node join rate for current phase
*/
getNodeJoinRate(phase) {
const rates = {
genesis: 0.3, // Slow initial growth
transition: 0.5, // Accelerating growth
maturity: 0.7, // Peak growth
'post-genesis': 0.4 // Stable growth
};
return rates[phase] || 0.3;
}
/**
* Check if a phase transition occurred
*/
checkPhaseTransition() {
const count = this.nodes.size;
const previousPhase = this.phases.currentPhase;
const currentPhase = this.getCurrentPhase();
if (previousPhase !== currentPhase) {
this.phases.transition(currentPhase);
this.phaseTransitions.push({
from: previousPhase,
to: currentPhase,
tick: this.currentTick,
nodeCount: count,
totalCompute: this.totalComputeHours,
timestamp: Date.now()
});
this.logEvent('phase_transition', {
from: previousPhase,
to: currentPhase,
nodeCount: count
});
console.log(`\n🔄 Phase Transition: ${previousPhase}${currentPhase} (${count} nodes)`);
}
}
/**
* Update network-wide metrics
*/
updateMetrics() {
const activeNodes = this.getActiveNodes();
const nodeCount = activeNodes.length;
if (nodeCount === 0) return;
let totalTasks = 0;
let totalSubmitted = 0;
let totalRuv = 0;
let totalLatency = 0;
let totalSuccess = 0;
for (const node of activeNodes) {
totalTasks += node.tasksCompleted;
totalSubmitted += node.tasksSubmitted;
totalRuv += node.ruvEarned;
totalLatency += node.avgLatency;
totalSuccess += node.successRate;
}
this.metrics = {
totalTasksCompleted: totalTasks,
totalTasksSubmitted: totalSubmitted,
totalRuvCirculating: totalRuv,
averageLatency: totalLatency / nodeCount,
averageSuccessRate: totalSuccess / nodeCount,
activeNodeCount: nodeCount,
genesisNodeCount: activeNodes.filter(n => n.isGenesis).length,
networkHealth: this.calculateNetworkHealth(activeNodes),
};
}
/**
* Calculate overall network health score (0-1)
*/
calculateNetworkHealth(nodes) {
if (nodes.length === 0) return 0;
// Factors: connectivity, success rate, economic velocity
const avgConnections = nodes.reduce((sum, n) => sum + n.connections.size, 0) / nodes.length;
const avgSuccess = nodes.reduce((sum, n) => sum + n.successRate, 0) / nodes.length;
const economicVelocity = this.economics.getVelocity();
const connectivityScore = Math.min(1.0, avgConnections / 20); // Target 20 connections
const reliabilityScore = avgSuccess;
const economicScore = Math.min(1.0, economicVelocity / 0.5); // Target 0.5 velocity
return (connectivityScore * 0.3 + reliabilityScore * 0.4 + economicScore * 0.3);
}
/**
* Get all active nodes
*/
getActiveNodes() {
return Array.from(this.nodes.values()).filter(n => n.active);
}
/**
* Log an event
*/
logEvent(type, data) {
this.events.push({
type,
tick: this.currentTick,
timestamp: Date.now(),
...data
});
}
/**
* Log progress to console
*/
logProgress() {
const phase = this.getCurrentPhase();
const activeNodes = this.getActiveNodes();
const genesisActive = activeNodes.filter(n => n.isGenesis).length;
console.log(
`📊 Tick ${this.currentTick} | ` +
`Phase: ${phase.toUpperCase()} | ` +
`Nodes: ${activeNodes.length} (${genesisActive} genesis) | ` +
`Compute: ${Math.floor(this.totalComputeHours)}h | ` +
`Health: ${(this.metrics.networkHealth * 100).toFixed(1)}%`
);
}
/**
* Generate final simulation report
*/
generateReport() {
const report = {
summary: {
totalTicks: this.currentTick,
totalNodes: this.nodes.size,
activeNodes: this.getActiveNodes().length,
totalComputeHours: this.totalComputeHours,
finalPhase: this.getCurrentPhase(),
simulationDuration: Date.now() - this.startTime,
},
metrics: this.metrics,
economics: this.economics.getReport(),
phases: {
transitions: this.phaseTransitions,
current: this.getCurrentPhase(),
},
nodes: {
genesis: Array.from(this.nodes.values())
.filter(n => n.isGenesis)
.map(n => n.getStats()),
regular: Array.from(this.nodes.values())
.filter(n => !n.isGenesis)
.slice(0, 100) // Sample of regular nodes
.map(n => n.getStats()),
},
events: this.events,
};
return report;
}
/**
* Export metrics as time series
*/
exportTimeSeries() {
// This would be populated during simulation
// For now, return current snapshot
return {
timestamp: Date.now(),
tick: this.currentTick,
nodeCount: this.nodes.size,
activeNodes: this.getActiveNodes().length,
totalCompute: this.totalComputeHours,
phase: this.getCurrentPhase(),
health: this.metrics.networkHealth,
...this.metrics,
};
}
}

View File

@@ -0,0 +1,314 @@
/**
* Network State Management
* Manages the P2P network state and phase transitions
*/
import { Cell, CellType, CellState } from './cell.js';
export enum NetworkPhase {
GENESIS = 'genesis', // 0 - 10K nodes
GROWTH = 'growth', // 10K - 50K nodes
MATURATION = 'maturation', // 50K - 100K nodes
INDEPENDENCE = 'independence', // 100K+ nodes
}
export interface NetworkConfig {
genesisNodeCount: number;
targetNodeCount: number;
nodesPerTick: number;
taskGenerationRate: number;
baseTaskReward: number;
connectionCost: number;
maxConnectionsPerNode: number;
}
export class Network {
public cells: Map<string, Cell>;
public currentPhase: NetworkPhase;
public currentTick: number;
public config: NetworkConfig;
public genesisCells: Set<string>;
private taskQueue: number[];
constructor(config?: Partial<NetworkConfig>) {
this.cells = new Map();
this.currentPhase = NetworkPhase.GENESIS;
this.currentTick = 0;
this.genesisCells = new Set();
this.taskQueue = [];
this.config = {
genesisNodeCount: config?.genesisNodeCount ?? 100,
targetNodeCount: config?.targetNodeCount ?? 120000,
nodesPerTick: config?.nodesPerTick ?? 10,
taskGenerationRate: config?.taskGenerationRate ?? 5,
baseTaskReward: config?.baseTaskReward ?? 1.0,
connectionCost: config?.connectionCost ?? 0.5,
maxConnectionsPerNode: config?.maxConnectionsPerNode ?? 50,
};
}
/**
* Initialize network with genesis nodes
*/
public initialize(): void {
console.log(`Initializing network with ${this.config.genesisNodeCount} genesis nodes...`);
for (let i = 0; i < this.config.genesisNodeCount; i++) {
const cell = new Cell(CellType.GENESIS, this.currentTick, {
computePower: 0.8 + Math.random() * 0.2, // Genesis nodes are powerful
bandwidth: 0.8 + Math.random() * 0.2,
reliability: 0.9 + Math.random() * 0.1,
storage: 0.8 + Math.random() * 0.2,
});
this.cells.set(cell.id, cell);
this.genesisCells.add(cell.id);
}
// Connect genesis nodes to each other (mesh topology)
this.connectGenesisNodes();
}
/**
* Connect all genesis nodes to each other
*/
private connectGenesisNodes(): void {
const genesisArray = Array.from(this.genesisCells);
for (let i = 0; i < genesisArray.length; i++) {
for (let j = i + 1; j < genesisArray.length; j++) {
const cell1 = this.cells.get(genesisArray[i])!;
const cell2 = this.cells.get(genesisArray[j])!;
cell1.connectTo(cell2.id);
cell2.connectTo(cell1.id);
}
}
}
/**
* Add new regular nodes to the network
*/
public spawnNodes(count: number): void {
for (let i = 0; i < count; i++) {
const cell = new Cell(CellType.REGULAR, this.currentTick);
this.cells.set(cell.id, cell);
// Connect to random existing nodes (preferential attachment)
this.connectNewNode(cell);
}
}
/**
* Connect a new node to the network
*/
private connectNewNode(newCell: Cell): void {
const connectionCount = Math.min(
5 + Math.floor(Math.random() * 5),
this.config.maxConnectionsPerNode
);
const potentialTargets = Array.from(this.cells.values())
.filter(c => c.id !== newCell.id)
.filter(c => {
// In Phase 2+, genesis nodes don't accept new connections
if (this.currentPhase !== NetworkPhase.GENESIS && c.type === CellType.GENESIS) {
return false;
}
return c.state === CellState.ACTIVE && c.connectedCells.size < this.config.maxConnectionsPerNode;
});
// Preferential attachment: higher fitness = more likely to connect
const selectedTargets = this.selectPreferentialTargets(potentialTargets, connectionCount);
for (const target of selectedTargets) {
newCell.connectTo(target.id);
target.connectTo(newCell.id);
// Connection costs energy
newCell.spendEnergy(this.config.connectionCost);
target.spendEnergy(this.config.connectionCost);
}
}
/**
* Select targets using preferential attachment
*/
private selectPreferentialTargets(candidates: Cell[], count: number): Cell[] {
if (candidates.length <= count) {
return candidates;
}
const selected: Cell[] = [];
const weights = candidates.map(c => c.getFitnessScore() * (1 + c.connectedCells.size));
const totalWeight = weights.reduce((sum, w) => sum + w, 0);
for (let i = 0; i < count && candidates.length > 0; i++) {
let random = Math.random() * totalWeight;
let selectedIndex = 0;
for (let j = 0; j < weights.length; j++) {
random -= weights[j];
if (random <= 0) {
selectedIndex = j;
break;
}
}
selected.push(candidates[selectedIndex]);
candidates.splice(selectedIndex, 1);
weights.splice(selectedIndex, 1);
}
return selected;
}
/**
* Generate tasks for the network
*/
private generateTasks(): void {
const tasksToGenerate = Math.floor(
this.cells.size * this.config.taskGenerationRate * Math.random()
);
for (let i = 0; i < tasksToGenerate; i++) {
// Task complexity between 0.1 and 1.0
this.taskQueue.push(0.1 + Math.random() * 0.9);
}
}
/**
* Distribute tasks to capable cells
*/
private distributeTasks(): void {
const activeCells = Array.from(this.cells.values())
.filter(c => c.state === CellState.ACTIVE);
while (this.taskQueue.length > 0 && activeCells.length > 0) {
const task = this.taskQueue.shift()!;
// Select cell based on fitness and availability
const selectedCell = activeCells[Math.floor(Math.random() * activeCells.length)];
selectedCell.processTask(task, this.config.baseTaskReward);
}
}
/**
* Update network phase based on node count
*/
private updatePhase(): void {
const nodeCount = this.cells.size;
const oldPhase = this.currentPhase;
if (nodeCount >= 100000) {
this.currentPhase = NetworkPhase.INDEPENDENCE;
} else if (nodeCount >= 50000) {
this.currentPhase = NetworkPhase.MATURATION;
} else if (nodeCount >= 10000) {
this.currentPhase = NetworkPhase.GROWTH;
} else {
this.currentPhase = NetworkPhase.GENESIS;
}
if (oldPhase !== this.currentPhase) {
console.log(`\n🔄 PHASE TRANSITION: ${oldPhase}${this.currentPhase} (${nodeCount} nodes)`);
this.onPhaseTransition();
}
}
/**
* Handle phase transition events
*/
private onPhaseTransition(): void {
// Update all cells based on new phase
this.cells.forEach(cell => cell.updateState(this.cells.size));
// Phase-specific actions
switch (this.currentPhase) {
case NetworkPhase.GROWTH:
console.log(' → Genesis nodes reducing 10x multiplier...');
break;
case NetworkPhase.MATURATION:
console.log(' → Genesis nodes entering READ-ONLY mode...');
break;
case NetworkPhase.INDEPENDENCE:
console.log(' → Genesis nodes RETIRED. Network is independent!');
break;
}
}
/**
* Simulate one tick of the network
*/
public tick(): void {
this.currentTick++;
// Spawn new nodes (if not at target)
if (this.cells.size < this.config.targetNodeCount) {
const nodesToSpawn = Math.min(
this.config.nodesPerTick,
this.config.targetNodeCount - this.cells.size
);
this.spawnNodes(nodesToSpawn);
}
// Generate and distribute tasks
this.generateTasks();
this.distributeTasks();
// Update all cells
this.cells.forEach(cell => {
cell.tick();
cell.updateState(this.cells.size);
});
// Check for phase transitions
this.updatePhase();
}
/**
* Get network statistics
*/
public getStats() {
const cells = Array.from(this.cells.values());
const genesisCells = cells.filter(c => c.type === CellType.GENESIS);
const regularCells = cells.filter(c => c.type === CellType.REGULAR);
const totalEnergy = cells.reduce((sum, c) => sum + c.energy, 0);
const totalEarned = cells.reduce((sum, c) => sum + c.metrics.energyEarned, 0);
const totalSpent = cells.reduce((sum, c) => sum + c.metrics.energySpent, 0);
const totalTasks = cells.reduce((sum, c) => sum + c.metrics.tasksCompleted, 0);
return {
tick: this.currentTick,
phase: this.currentPhase,
nodeCount: this.cells.size,
genesisNodes: {
count: genesisCells.length,
active: genesisCells.filter(c => c.state === CellState.ACTIVE).length,
readOnly: genesisCells.filter(c => c.state === CellState.READ_ONLY).length,
retired: genesisCells.filter(c => c.state === CellState.RETIRED).length,
avgMultiplier: genesisCells.reduce((sum, c) => sum + c.genesisMultiplier, 0) / genesisCells.length,
},
regularNodes: {
count: regularCells.length,
},
economy: {
totalEnergy,
totalEarned,
totalSpent,
netEnergy: totalEarned - totalSpent,
avgEnergyPerNode: totalEnergy / this.cells.size,
},
tasks: {
completed: totalTasks,
queued: this.taskQueue.length,
avgPerNode: totalTasks / this.cells.size,
},
network: {
avgConnections: cells.reduce((sum, c) => sum + c.connectedCells.size, 0) / this.cells.size,
avgSuccessRate: cells.reduce((sum, c) => sum + c.metrics.successRate, 0) / this.cells.size,
},
};
}
}

View File

@@ -0,0 +1,171 @@
/**
* Simulated Edge-Net Node
* Represents a single node in the distributed network
*/
export class SimNode {
constructor(id, joinedAt, isGenesis = false) {
this.id = id;
this.joinedAt = joinedAt;
this.isGenesis = isGenesis;
// Node state
this.active = true;
this.uptime = 0;
this.lastSeen = joinedAt;
// Economic state
this.ruvEarned = 0;
this.ruvSpent = 0;
this.ruvStaked = 0;
// Performance metrics
this.tasksCompleted = 0;
this.tasksSubmitted = 0;
this.successRate = 0.95;
this.avgLatency = 100 + Math.random() * 200; // ms
// Network state
this.connections = new Set();
this.maxConnections = isGenesis ? 1000 : 50;
this.reputation = 1.0;
// Contribution metrics
this.cpuContribution = 0.2 + Math.random() * 0.3; // 20-50%
this.totalComputeHours = 0;
}
/**
* Update node state for a time step
*/
tick(deltaTime, networkCompute, currentPhase) {
if (!this.active) return;
this.uptime += deltaTime;
this.lastSeen = Date.now();
// Calculate contribution for this tick
const hoursThisTick = deltaTime / 3600000; // ms to hours
const contribution = this.cpuContribution * hoursThisTick;
this.totalComputeHours += contribution;
// Simulate task completion
const tasksThisTick = Math.floor(Math.random() * 3);
if (tasksThisTick > 0) {
this.tasksCompleted += tasksThisTick;
// Calculate rewards with multiplier
const baseReward = tasksThisTick * 10; // 10 rUv per task
const multiplier = this.calculateMultiplier(networkCompute, currentPhase);
const reward = Math.floor(baseReward * multiplier);
this.ruvEarned += reward;
}
// Simulate task submission (nodes also consume)
if (Math.random() < 0.1) { // 10% chance per tick
this.tasksSubmitted += 1;
const cost = 5 + Math.floor(Math.random() * 15); // 5-20 rUv
if (this.getBalance() >= cost) {
this.ruvSpent += cost;
}
}
// Update success rate (small random walk)
this.successRate = Math.max(0.7, Math.min(0.99,
this.successRate + (Math.random() - 0.5) * 0.01
));
// Genesis nodes in transition phase have connection limits
if (this.isGenesis && currentPhase === 'transition') {
this.maxConnections = Math.max(100, this.maxConnections - 1);
}
// Genesis nodes become read-only in maturity phase
if (this.isGenesis && currentPhase === 'maturity') {
this.maxConnections = 0; // No new connections
}
// Genesis nodes retire in post-genesis
if (this.isGenesis && currentPhase === 'post-genesis') {
this.active = false;
}
}
/**
* Calculate contribution multiplier based on network state
*/
calculateMultiplier(networkCompute, phase) {
// Base multiplier from contribution curve
const MAX_BONUS = 10.0;
const DECAY_CONSTANT = 1000000.0;
const decay = Math.exp(-networkCompute / DECAY_CONSTANT);
const baseMultiplier = 1.0 + (MAX_BONUS - 1.0) * decay;
// Early adopter bonus for genesis nodes
let earlyBonus = 1.0;
if (this.isGenesis && phase === 'genesis') {
earlyBonus = 10.0; // 10x for genesis contributors
} else if (this.isGenesis && phase === 'transition') {
earlyBonus = 5.0 - (networkCompute / 1000000.0) * 4.0; // Decay from 5x to 1x
earlyBonus = Math.max(1.0, earlyBonus);
}
return baseMultiplier * earlyBonus;
}
/**
* Get current rUv balance
*/
getBalance() {
return Math.max(0, this.ruvEarned - this.ruvSpent - this.ruvStaked);
}
/**
* Connect to another node
*/
connectTo(nodeId) {
if (this.connections.size < this.maxConnections) {
this.connections.add(nodeId);
return true;
}
return false;
}
/**
* Disconnect from a node
*/
disconnect(nodeId) {
this.connections.delete(nodeId);
}
/**
* Check if node can accept connections
*/
canAcceptConnections() {
return this.active && this.connections.size < this.maxConnections;
}
/**
* Get node statistics
*/
getStats() {
return {
id: this.id,
isGenesis: this.isGenesis,
active: this.active,
uptime: this.uptime,
ruvBalance: this.getBalance(),
ruvEarned: this.ruvEarned,
ruvSpent: this.ruvSpent,
tasksCompleted: this.tasksCompleted,
tasksSubmitted: this.tasksSubmitted,
successRate: this.successRate,
reputation: this.reputation,
connections: this.connections.size,
maxConnections: this.maxConnections,
totalComputeHours: this.totalComputeHours,
};
}
}

View File

@@ -0,0 +1,193 @@
/**
* Phase Management for Network Lifecycle
* Tracks and validates phase transitions
*/
export class PhaseManager {
constructor() {
this.currentPhase = 'genesis';
this.phaseHistory = [];
this.phaseMetrics = new Map();
this.initializePhases();
}
/**
* Initialize phase definitions
*/
initializePhases() {
this.phases = {
genesis: {
name: 'Genesis Phase',
nodeRange: [0, 10000],
description: 'Network bootstrap with genesis nodes',
features: [
'Genesis node initialization',
'Early adopter multiplier (10x)',
'Network bootstrap',
'Initial task distribution',
'Security learning initialization',
],
validations: [
{ metric: 'genesisNodesActive', min: 1, description: 'At least 1 genesis node active' },
{ metric: 'earlyMultiplier', min: 5.0, description: 'High early adopter multiplier' },
],
},
transition: {
name: 'Transition Phase',
nodeRange: [10000, 50000],
description: 'Genesis sunset preparation',
features: [
'Genesis node connection limiting',
'Network resilience testing',
'Task routing optimization',
'Economic sustainability threshold',
'Topology self-organization',
],
validations: [
{ metric: 'genesisConnectionLimit', max: 500, description: 'Genesis connections limited' },
{ metric: 'networkResilience', min: 0.7, description: 'Network resilient without full genesis' },
{ metric: 'taskRoutingSuccess', min: 0.85, description: 'Efficient task routing' },
],
},
maturity: {
name: 'Maturity Phase',
nodeRange: [50000, 100000],
description: 'Genesis read-only mode',
features: [
'Genesis nodes read-only',
'Full network self-sustenance',
'Economic health monitoring',
'Security threat response',
'Founder tribute distribution',
],
validations: [
{ metric: 'genesisReadOnly', exact: true, description: 'Genesis nodes read-only' },
{ metric: 'economicHealth', min: 0.75, description: 'Healthy economic metrics' },
{ metric: 'selfSustaining', exact: true, description: 'Network self-sustaining' },
],
},
'post-genesis': {
name: 'Post-Genesis Phase',
nodeRange: [100000, Infinity],
description: 'Full decentralization',
features: [
'Genesis retirement complete',
'Independent network operation',
'Long-term stability',
'Economic equilibrium',
'Community governance',
],
validations: [
{ metric: 'genesisRetired', exact: true, description: 'All genesis nodes retired' },
{ metric: 'networkStability', min: 0.8, description: 'Stable network operation' },
{ metric: 'economicEquilibrium', min: 0.7, description: 'Economic equilibrium reached' },
],
},
};
}
/**
* Transition to a new phase
*/
transition(newPhase) {
if (this.currentPhase === newPhase) return;
const previousPhase = this.currentPhase;
this.currentPhase = newPhase;
this.phaseHistory.push({
from: previousPhase,
to: newPhase,
timestamp: Date.now(),
});
console.log(`\n${'='.repeat(60)}`);
console.log(`🔄 PHASE TRANSITION: ${previousPhase}${newPhase}`);
console.log(`${'='.repeat(60)}`);
console.log(`\n${this.phases[newPhase].description}\n`);
console.log('Features:');
this.phases[newPhase].features.forEach(f => console.log(`${f}`));
console.log('');
}
/**
* Get current phase definition
*/
getCurrentPhaseInfo() {
return this.phases[this.currentPhase];
}
/**
* Validate phase metrics
*/
validatePhase(metrics) {
const phase = this.phases[this.currentPhase];
if (!phase) return { valid: false, errors: ['Unknown phase'] };
const errors = [];
const validations = phase.validations || [];
for (const validation of validations) {
const value = metrics[validation.metric];
if (validation.min !== undefined && value < validation.min) {
errors.push(`${validation.description}: ${value} < ${validation.min}`);
}
if (validation.max !== undefined && value > validation.max) {
errors.push(`${validation.description}: ${value} > ${validation.max}`);
}
if (validation.exact !== undefined && value !== validation.exact) {
errors.push(`${validation.description}: ${value} !== ${validation.exact}`);
}
}
return {
valid: errors.length === 0,
errors,
phase: this.currentPhase,
validations,
};
}
/**
* Record phase metrics
*/
recordMetrics(phase, metrics) {
if (!this.phaseMetrics.has(phase)) {
this.phaseMetrics.set(phase, []);
}
this.phaseMetrics.get(phase).push({
timestamp: Date.now(),
...metrics,
});
}
/**
* Get phase report
*/
getReport() {
return {
currentPhase: this.currentPhase,
phaseInfo: this.getCurrentPhaseInfo(),
history: this.phaseHistory,
metrics: Object.fromEntries(this.phaseMetrics),
};
}
/**
* Get expected phase for node count
*/
getExpectedPhase(nodeCount) {
for (const [phaseName, phase] of Object.entries(this.phases)) {
const [min, max] = phase.nodeRange;
if (nodeCount >= min && nodeCount < max) {
return phaseName;
}
}
return 'post-genesis';
}
}

View File

@@ -0,0 +1,202 @@
/**
* Phase Transition Logic
* Manages lifecycle phases and transition conditions
*/
import { Network, NetworkPhase } from './network.js';
import { MetricsCollector } from './metrics.js';
import { Cell, CellType, CellState } from './cell.js';
export interface PhaseTransitionCondition {
minNodes: number;
maxNodes: number;
requiredDuration?: number;
customCheck?: (network: Network) => boolean;
}
export class PhaseManager {
private network: Network;
private metrics: MetricsCollector;
private conditions: Map<NetworkPhase, PhaseTransitionCondition>;
private lastPhase: NetworkPhase;
constructor(network: Network, metrics: MetricsCollector) {
this.network = network;
this.metrics = metrics;
this.lastPhase = NetworkPhase.GENESIS;
this.conditions = new Map<NetworkPhase, PhaseTransitionCondition>([
[NetworkPhase.GENESIS, {
minNodes: 0,
maxNodes: 10000,
}],
[NetworkPhase.GROWTH, {
minNodes: 10000,
maxNodes: 50000,
customCheck: (net: Network) => {
// Verify genesis nodes are still active but reducing multiplier
const genesisCells = Array.from(net.cells.values())
.filter((c: Cell) => c.type === CellType.GENESIS);
const avgMultiplier = genesisCells.reduce((sum, c) => sum + c.genesisMultiplier, 0) / genesisCells.length;
return avgMultiplier < 10 && avgMultiplier > 1;
},
}],
[NetworkPhase.MATURATION, {
minNodes: 50000,
maxNodes: 100000,
customCheck: (net: Network) => {
// Verify genesis nodes are entering read-only mode
const genesisCells = Array.from(net.cells.values())
.filter((c: Cell) => c.type === CellType.GENESIS);
const readOnlyCount = genesisCells.filter(c => c.state === CellState.READ_ONLY).length;
return readOnlyCount >= genesisCells.length * 0.5; // At least 50% read-only
},
}],
[NetworkPhase.INDEPENDENCE, {
minNodes: 100000,
maxNodes: Infinity,
customCheck: (net: Network) => {
// Verify genesis nodes are retired
const genesisCells = Array.from(net.cells.values())
.filter((c: Cell) => c.type === CellType.GENESIS);
const retiredCount = genesisCells.filter(c => c.state === CellState.RETIRED).length;
return retiredCount >= genesisCells.length * 0.8; // At least 80% retired
},
}],
]);
}
/**
* Check if network should transition to next phase
*/
public checkTransition(): boolean {
const currentPhase = this.network.currentPhase;
const nodeCount = this.network.cells.size;
// Determine target phase based on node count
let targetPhase = NetworkPhase.GENESIS;
if (nodeCount >= 100000) {
targetPhase = NetworkPhase.INDEPENDENCE;
} else if (nodeCount >= 50000) {
targetPhase = NetworkPhase.MATURATION;
} else if (nodeCount >= 10000) {
targetPhase = NetworkPhase.GROWTH;
}
// If phase changed, validate transition
if (targetPhase !== currentPhase) {
const condition = this.conditions.get(targetPhase);
if (condition) {
// Check node count bounds
if (nodeCount < condition.minNodes || nodeCount >= condition.maxNodes) {
return false;
}
// Check custom conditions
if (condition.customCheck && !condition.customCheck(this.network)) {
return false;
}
// Valid transition
this.onTransition(currentPhase, targetPhase);
return true;
}
}
return false;
}
/**
* Handle phase transition
*/
private onTransition(fromPhase: NetworkPhase, toPhase: NetworkPhase): void {
console.log(`\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━`);
console.log(`🔄 PHASE TRANSITION: ${fromPhase.toUpperCase()}${toPhase.toUpperCase()}`);
console.log(`━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━`);
// Notify metrics collector
this.metrics.onPhaseTransition(fromPhase, toPhase);
// Log phase-specific information
this.logPhaseInfo(toPhase);
this.lastPhase = toPhase;
}
/**
* Log phase-specific information
*/
private logPhaseInfo(phase: NetworkPhase): void {
const stats = this.network.getStats();
console.log(`📊 Network Status:`);
console.log(` Nodes: ${stats.nodeCount.toLocaleString()}`);
console.log(` Genesis Nodes: ${stats.genesisNodes.count}`);
console.log(` Avg Connections: ${stats.network.avgConnections.toFixed(2)}`);
console.log(` Total Energy: ${stats.economy.totalEnergy.toFixed(2)} rUv`);
switch (phase) {
case NetworkPhase.GENESIS:
console.log(`\n🌱 Genesis Phase:`);
console.log(` - Genesis nodes establishing network`);
console.log(` - 10x energy multiplier active`);
console.log(` - Target: 10,000 nodes`);
break;
case NetworkPhase.GROWTH:
console.log(`\n🌿 Growth Phase:`);
console.log(` - Genesis multiplier: ${stats.genesisNodes.avgMultiplier.toFixed(2)}x`);
console.log(` - Genesis nodes reducing connections`);
console.log(` - Network self-organizing`);
console.log(` - Target: 50,000 nodes`);
break;
case NetworkPhase.MATURATION:
console.log(`\n🌳 Maturation Phase:`);
console.log(` - Genesis nodes: ${stats.genesisNodes.readOnly} read-only`);
console.log(` - Network operating independently`);
console.log(` - Economic sustainability: ${(stats.economy.totalEarned / Math.max(stats.economy.totalSpent, 1)).toFixed(2)}x`);
console.log(` - Target: 100,000 nodes`);
break;
case NetworkPhase.INDEPENDENCE:
console.log(`\n🚀 Independence Phase:`);
console.log(` - Genesis nodes: ${stats.genesisNodes.retired} retired`);
console.log(` - Pure P2P operation`);
console.log(` - Network fully autonomous`);
console.log(` - Target: Long-term stability`);
break;
}
console.log(`━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n`);
}
/**
* Get phase progress (0-1)
*/
public getPhaseProgress(): number {
const condition = this.conditions.get(this.network.currentPhase);
if (!condition) return 0;
const nodeCount = this.network.cells.size;
const range = condition.maxNodes - condition.minNodes;
const progress = (nodeCount - condition.minNodes) / range;
return Math.max(0, Math.min(1, progress));
}
/**
* Get estimated ticks to next phase
*/
public getTicksToNextPhase(): number {
const condition = this.conditions.get(this.network.currentPhase);
if (!condition || condition.maxNodes === Infinity) return -1;
const nodeCount = this.network.cells.size;
const nodesNeeded = condition.maxNodes - nodeCount;
const ticksNeeded = Math.ceil(nodesNeeded / this.network.config.nodesPerTick);
return Math.max(0, ticksNeeded);
}
}

View File

@@ -0,0 +1,246 @@
/**
* Report Generation
* Generates comprehensive JSON reports of simulation results
*/
import { writeFileSync } from 'fs';
import { Network } from './network.js';
import { MetricsCollector, PhaseMetrics } from './metrics.js';
export interface SimulationReport {
metadata: {
timestamp: string;
simulationVersion: string;
duration: number;
totalTicks: number;
};
configuration: {
genesisNodeCount: number;
targetNodeCount: number;
nodesPerTick: number;
taskGenerationRate: number;
baseTaskReward: number;
};
summary: {
phasesCompleted: number;
totalPassed: boolean;
phasesPassed: number;
phasesTotal: number;
finalNodeCount: number;
finalPhase: string;
};
phases: {
[key: string]: PhaseMetrics;
};
finalState: {
nodeCount: number;
genesisNodes: any;
economy: any;
network: any;
topPerformers: any[];
};
validation: {
overallPassed: boolean;
criticalIssues: string[];
warnings: string[];
successes: string[];
};
}
export class ReportGenerator {
private network: Network;
private metrics: MetricsCollector;
private startTime: number;
constructor(network: Network, metrics: MetricsCollector) {
this.network = network;
this.metrics = metrics;
this.startTime = Date.now();
}
/**
* Generate comprehensive simulation report
*/
public generateReport(): SimulationReport {
const endTime = Date.now();
const stats = this.network.getStats();
const allMetrics = this.metrics.getAllMetrics();
const overallSuccess = this.metrics.getOverallSuccess();
// Organize metrics by phase
const phaseMetrics: { [key: string]: PhaseMetrics } = {};
allMetrics.forEach(m => {
phaseMetrics[m.phase] = m;
});
// Get top performing nodes
const topPerformers = this.getTopPerformers(10);
// Collect validation issues
const validation = this.collectValidation(allMetrics);
const report: SimulationReport = {
metadata: {
timestamp: new Date().toISOString(),
simulationVersion: '1.0.0',
duration: endTime - this.startTime,
totalTicks: this.network.currentTick,
},
configuration: {
genesisNodeCount: this.network.config.genesisNodeCount,
targetNodeCount: this.network.config.targetNodeCount,
nodesPerTick: this.network.config.nodesPerTick,
taskGenerationRate: this.network.config.taskGenerationRate,
baseTaskReward: this.network.config.baseTaskReward,
},
summary: {
phasesCompleted: allMetrics.length,
totalPassed: overallSuccess.passed,
phasesPassed: overallSuccess.totalPassed,
phasesTotal: overallSuccess.totalPhases,
finalNodeCount: stats.nodeCount,
finalPhase: this.network.currentPhase,
},
phases: phaseMetrics,
finalState: {
nodeCount: stats.nodeCount,
genesisNodes: stats.genesisNodes,
economy: stats.economy,
network: stats.network,
topPerformers,
},
validation,
};
return report;
}
/**
* Get top performing nodes
*/
private getTopPerformers(count: number): any[] {
const cells = Array.from(this.network.cells.values());
return cells
.sort((a, b) => {
const scoreA = a.metrics.energyEarned - a.metrics.energySpent;
const scoreB = b.metrics.energyEarned - b.metrics.energySpent;
return scoreB - scoreA;
})
.slice(0, count)
.map(cell => ({
id: cell.id.substring(0, 8),
type: cell.type,
netEnergy: cell.metrics.energyEarned - cell.metrics.energySpent,
tasksCompleted: cell.metrics.tasksCompleted,
successRate: (cell.metrics.successRate * 100).toFixed(1) + '%',
connections: cell.connectedCells.size,
fitnessScore: cell.getFitnessScore().toFixed(3),
}));
}
/**
* Collect all validation issues
*/
private collectValidation(allMetrics: PhaseMetrics[]): {
overallPassed: boolean;
criticalIssues: string[];
warnings: string[];
successes: string[];
} {
const criticalIssues: string[] = [];
const warnings: string[] = [];
const successes: string[] = [];
allMetrics.forEach(metrics => {
if (!metrics.validation.passed) {
criticalIssues.push(`${metrics.phase.toUpperCase()} phase failed validation`);
}
metrics.validation.reasons.forEach(reason => {
if (reason.startsWith('✓')) {
successes.push(`${metrics.phase}: ${reason}`);
} else if (reason.includes('too low') || reason.includes('insufficient')) {
warnings.push(`${metrics.phase}: ${reason}`);
} else {
criticalIssues.push(`${metrics.phase}: ${reason}`);
}
});
});
return {
overallPassed: criticalIssues.length === 0,
criticalIssues,
warnings,
successes,
};
}
/**
* Save report to file
*/
public saveReport(filepath: string): void {
const report = this.generateReport();
writeFileSync(filepath, JSON.stringify(report, null, 2), 'utf-8');
console.log(`\n📄 Report saved to: ${filepath}`);
}
/**
* Print summary to console
*/
public printSummary(): void {
const report = this.generateReport();
console.log('\n╔════════════════════════════════════════════════════════════╗');
console.log('║ EDGE-NET LIFECYCLE SIMULATION REPORT ║');
console.log('╚════════════════════════════════════════════════════════════╝\n');
console.log('📊 SUMMARY:');
console.log(` Duration: ${(report.metadata.duration / 1000).toFixed(2)}s`);
console.log(` Total Ticks: ${report.metadata.totalTicks.toLocaleString()}`);
console.log(` Final Nodes: ${report.summary.finalNodeCount.toLocaleString()}`);
console.log(` Final Phase: ${report.summary.finalPhase.toUpperCase()}`);
console.log(` Phases Passed: ${report.summary.phasesPassed}/${report.summary.phasesTotal}`);
console.log(` Overall Result: ${report.summary.totalPassed ? '✅ PASSED' : '❌ FAILED'}\n`);
console.log('📈 PHASE RESULTS:');
Object.entries(report.phases).forEach(([phase, metrics]) => {
const icon = metrics.validation.passed ? '✅' : '❌';
console.log(` ${icon} ${phase.toUpperCase()}:`);
console.log(` Nodes: ${metrics.nodeCount.start.toLocaleString()}${metrics.nodeCount.end.toLocaleString()}`);
console.log(` Energy: ${metrics.energy.netEnergy.toFixed(2)} rUv (${metrics.energy.sustainability.toFixed(2)}x sustainable)`);
console.log(` Tasks: ${metrics.network.tasksCompleted.toLocaleString()} completed`);
console.log(` Success Rate: ${(metrics.network.avgSuccessRate * 100).toFixed(1)}%`);
});
console.log('\n🏆 TOP PERFORMERS:');
report.finalState.topPerformers.slice(0, 5).forEach((node, i) => {
console.log(` ${i + 1}. ${node.id} (${node.type})`);
console.log(` Net Energy: ${node.netEnergy.toFixed(2)} rUv | Tasks: ${node.tasksCompleted} | Success: ${node.successRate}`);
});
if (report.validation.criticalIssues.length > 0) {
console.log('\n🚨 CRITICAL ISSUES:');
report.validation.criticalIssues.forEach(issue => {
console.log(`${issue}`);
});
}
if (report.validation.warnings.length > 0) {
console.log('\n⚠ WARNINGS:');
report.validation.warnings.slice(0, 5).forEach(warning => {
console.log(` ⚠️ ${warning}`);
});
if (report.validation.warnings.length > 5) {
console.log(` ... and ${report.validation.warnings.length - 5} more warnings`);
}
}
console.log('\n✅ SUCCESSES:');
report.validation.successes.slice(0, 10).forEach(success => {
console.log(` ${success}`);
});
console.log('\n╚════════════════════════════════════════════════════════════╝\n');
}
}

View File

@@ -0,0 +1,163 @@
#!/usr/bin/env node
/**
* Main Simulation Engine
* Orchestrates the complete edge-net lifecycle simulation
*/
import { Network, NetworkPhase } from './network.js';
import { MetricsCollector } from './metrics.js';
import { PhaseManager } from './phases.js';
import { ReportGenerator } from './report.js';
interface SimulationConfig {
verbose: boolean;
fast: boolean;
outputFile: string;
}
class EdgeNetSimulator {
private network: Network;
private metrics: MetricsCollector;
private phaseManager: PhaseManager;
private reportGenerator: ReportGenerator;
private config: SimulationConfig;
private progressInterval: number;
constructor(config: SimulationConfig) {
this.config = config;
this.progressInterval = config.fast ? 1000 : 100;
// Initialize components
this.network = new Network({
genesisNodeCount: 100,
targetNodeCount: 120000,
nodesPerTick: config.fast ? 100 : 10, // Faster node spawning in fast mode
taskGenerationRate: 5,
baseTaskReward: 1.0,
connectionCost: 0.5,
maxConnectionsPerNode: 50,
});
this.metrics = new MetricsCollector(this.network);
this.phaseManager = new PhaseManager(this.network, this.metrics);
this.reportGenerator = new ReportGenerator(this.network, this.metrics);
}
/**
* Run the complete simulation
*/
public async run(): Promise<void> {
console.log('╔════════════════════════════════════════════════════════════╗');
console.log('║ EDGE-NET LIFECYCLE SIMULATION - Starting... ║');
console.log('╚════════════════════════════════════════════════════════════╝\n');
console.log('⚙️ Configuration:');
console.log(` Genesis Nodes: ${this.network.config.genesisNodeCount}`);
console.log(` Target Nodes: ${this.network.config.targetNodeCount.toLocaleString()}`);
console.log(` Nodes/Tick: ${this.network.config.nodesPerTick}`);
console.log(` Mode: ${this.config.fast ? 'FAST' : 'NORMAL'}`);
console.log('');
// Initialize network with genesis nodes
this.network.initialize();
this.metrics.initialize();
console.log('🌱 Genesis nodes deployed. Starting simulation...\n');
let lastProgressUpdate = 0;
const startTime = Date.now();
// Main simulation loop
while (this.network.currentPhase !== NetworkPhase.INDEPENDENCE ||
this.network.cells.size < this.network.config.targetNodeCount) {
// Simulate one tick
this.network.tick();
this.metrics.collect();
this.phaseManager.checkTransition();
// Progress updates
if (this.network.currentTick - lastProgressUpdate >= this.progressInterval) {
this.printProgress();
lastProgressUpdate = this.network.currentTick;
}
// Safety check - don't run forever
if (this.network.currentTick > 50000) {
console.log('\n⚠ Simulation timeout reached (50,000 ticks)');
break;
}
}
const endTime = Date.now();
const duration = (endTime - startTime) / 1000;
console.log('\n✨ Simulation complete!\n');
console.log(` Total Ticks: ${this.network.currentTick.toLocaleString()}`);
console.log(` Duration: ${duration.toFixed(2)}s`);
console.log(` Final Nodes: ${this.network.cells.size.toLocaleString()}`);
console.log(` Final Phase: ${this.network.currentPhase.toUpperCase()}\n`);
// Finalize metrics
this.metrics.finalizeCurrent();
// Generate and save report
this.reportGenerator.printSummary();
this.reportGenerator.saveReport(this.config.outputFile);
// Exit with appropriate code
const report = this.reportGenerator.generateReport();
process.exit(report.summary.totalPassed ? 0 : 1);
}
/**
* Print simulation progress
*/
private printProgress(): void {
const stats = this.network.getStats();
const progress = this.phaseManager.getPhaseProgress();
const ticksToNext = this.phaseManager.getTicksToNextPhase();
if (this.config.verbose) {
console.log(`[Tick ${this.network.currentTick}] ${this.network.currentPhase.toUpperCase()}`);
console.log(` Nodes: ${stats.nodeCount.toLocaleString()} | Energy: ${stats.economy.totalEnergy.toFixed(2)} rUv`);
console.log(` Tasks: ${stats.tasks.completed.toLocaleString()} | Success: ${(stats.network.avgSuccessRate * 100).toFixed(1)}%`);
console.log(` Genesis: ${stats.genesisNodes.active} active, ${stats.genesisNodes.readOnly} read-only, ${stats.genesisNodes.retired} retired`);
console.log(` Progress: ${(progress * 100).toFixed(1)}% | Next phase: ${ticksToNext >= 0 ? `~${ticksToNext} ticks` : 'N/A'}`);
console.log('');
} else {
// Compact progress bar
const barLength = 40;
const filled = Math.floor(progress * barLength);
const bar = '█'.repeat(filled) + '░'.repeat(barLength - filled);
process.stdout.write(
`\r[${bar}] ${this.network.currentPhase.padEnd(12)} | ` +
`${stats.nodeCount.toLocaleString().padStart(7)} nodes | ` +
`${stats.tasks.completed.toLocaleString().padStart(8)} tasks | ` +
`Genesis: ${stats.genesisNodes.retired}/${stats.genesisNodes.count} retired`
);
}
}
}
// Parse command line arguments
function parseArgs(): SimulationConfig {
const args = process.argv.slice(2);
return {
verbose: args.includes('--verbose') || args.includes('-v'),
fast: args.includes('--fast') || args.includes('-f'),
outputFile: args.find(arg => arg.startsWith('--output='))?.split('=')[1] ||
'/workspaces/ruvector/examples/edge-net/sim/simulation-report.json',
};
}
// Run simulation
const config = parseArgs();
const simulator = new EdgeNetSimulator(config);
simulator.run().catch(error => {
console.error('❌ Simulation failed:', error);
process.exit(1);
});