UNPKG

@sschepis/resolang

Version:

ResoLang - Core quantum resonance computation library for browser and Node.js

712 lines (593 loc) 19.1 kB
/** * Network Synchronizer * * Offline-first synchronization with eventual coherence. * From whitepaper Section 6.5: * * State = (GMF_snapshot_id, ΔGMF, PL) * * On Join: * 1. Obtain latest GMF snapshot header and delta index * 2. Prime-resonant handshake to align channel frame * 3. Pull deltas; apply in order; update GMF_snapshot_id * 4. Rebase local LF against GMF (soft merge via resonance blending) * * Offline Operation: * - LF continues producing moments and local inserts into M_L * - Proposals append into PL with local proofs * - Background "reconnect" routine attempts resync * * On Reconnect: * 1. Pull missed GMF deltas * 2. Replay local PL proposals into the network * 3. Run coherent-commit evaluation; accept/reject */ import { Serializable } from '../core/interfaces'; import { JSONBuilder } from '../core/serialization'; import { toFixed } from '../utils'; import { MemoryObject, LocalProof, GlobalMemoryField, GMFDelta, GMFSnapshot } from './gmf'; import { PRRCChannel, PhaseReference } from './prrc'; import { DCCProtocol, DCCProposal } from './dcc'; // ============================================================================ // ID Generator // ============================================================================ let _syncIdCounter: i64 = 0; function generateId(prefix: string = "sync"): string { _syncIdCounter++; const timestamp = Date.now() as i64; return `${prefix}_${timestamp}_${_syncIdCounter}`; } // ============================================================================ // Sync Configuration // ============================================================================ /** * Network synchronizer configuration */ export class SyncConfig { // Connection settings reconnectIntervalMs: i64 = 5000; // 5 seconds maxReconnectAttempts: i32 = 10; // Sync settings deltaFetchBatchSize: i32 = 100; maxPendingProposals: i32 = 1000; // Merge settings resonanceBlendAlpha: f64 = 0.3; // Soft merge weight for remote conflictResolutionMode: string = "coherence"; // "coherence", "timestamp", "local" // Offline settings offlineProposalLogSize: i32 = 10000; autoReconnect: bool = true; constructor() {} } // ============================================================================ // Proposal Log Entry // ============================================================================ /** * Proposal log entry for offline operation * π_k = (Ω_k, meta, proofs, t_k) */ export class ProposalLogEntry implements Serializable { id: string; timestamp: i64; // Object and proofs object: MemoryObject; proof: LocalProof; // Metadata tickNumber: i64; coherenceAtProposal: f64; // Status status: string; // "pending", "submitted", "accepted", "rejected" submissionAttempts: i32; lastSubmissionTime: i64; constructor(object: MemoryObject, proof: LocalProof, tickNumber: i64) { this.id = generateId("pl"); this.timestamp = Date.now() as i64; this.object = object; this.proof = proof; this.tickNumber = tickNumber; this.coherenceAtProposal = proof.coherence; this.status = "pending"; this.submissionAttempts = 0; this.lastSubmissionTime = 0; } toJSON(): string { const builder = new JSONBuilder(); builder.startObject() .addStringField("id", this.id) .addNumberField("timestamp", f64(this.timestamp)) .addStringField("objectId", this.object.id) .addStringField("status", this.status) .addNumberField("submissionAttempts", f64(this.submissionAttempts)) .endObject(); return builder.build(); } toString(): string { return `PLEntry(${this.id.substring(0, 8)}, ${this.status})`; } } // ============================================================================ // Sync State // ============================================================================ /** * Current synchronization state * State = (GMF_snapshot_id, ΔGMF, PL) */ export class SyncState implements Serializable { // GMF state gmfSnapshotId: string; lastDeltaId: string; gmfVersion: i32; // Connection state connectionStatus: string; // "disconnected", "connecting", "connected", "syncing" lastConnectedTime: i64; lastSyncTime: i64; // Delta stream pendingDeltas: GMFDelta[]; appliedDeltaCount: i32; // Proposal log proposalLog: ProposalLogEntry[]; constructor() { this.gmfSnapshotId = ""; this.lastDeltaId = ""; this.gmfVersion = 0; this.connectionStatus = "disconnected"; this.lastConnectedTime = 0; this.lastSyncTime = 0; this.pendingDeltas = []; this.appliedDeltaCount = 0; this.proposalLog = []; } toJSON(): string { const builder = new JSONBuilder(); builder.startObject() .addStringField("gmfSnapshotId", this.gmfSnapshotId) .addStringField("lastDeltaId", this.lastDeltaId) .addNumberField("gmfVersion", f64(this.gmfVersion)) .addStringField("connectionStatus", this.connectionStatus) .addNumberField("pendingDeltaCount", f64(this.pendingDeltas.length)) .addNumberField("proposalLogSize", f64(this.proposalLog.length)) .endObject(); return builder.build(); } toString(): string { return `SyncState(${this.connectionStatus}, deltas=${this.pendingDeltas.length})`; } } // ============================================================================ // Sync Result // ============================================================================ /** * Result of a synchronization operation */ export class SyncResult implements Serializable { success: bool; timestamp: i64; // What was synced deltasApplied: i32; proposalsSubmitted: i32; proposalsAccepted: i32; proposalsRejected: i32; // Conflicts resolved conflictsDetected: i32; conflictsResolved: i32; // Errors errorMessage: string; constructor() { this.success = false; this.timestamp = Date.now() as i64; this.deltasApplied = 0; this.proposalsSubmitted = 0; this.proposalsAccepted = 0; this.proposalsRejected = 0; this.conflictsDetected = 0; this.conflictsResolved = 0; this.errorMessage = ""; } toJSON(): string { const builder = new JSONBuilder(); builder.startObject() .addBooleanField("success", this.success) .addNumberField("deltasApplied", f64(this.deltasApplied)) .addNumberField("proposalsSubmitted", f64(this.proposalsSubmitted)) .addNumberField("proposalsAccepted", f64(this.proposalsAccepted)) .addNumberField("proposalsRejected", f64(this.proposalsRejected)) .addNumberField("conflictsDetected", f64(this.conflictsDetected)) .addStringField("errorMessage", this.errorMessage) .endObject(); return builder.build(); } toString(): string { return `SyncResult(${this.success ? "ok" : "fail"}, deltas=${this.deltasApplied})`; } } // ============================================================================ // Network Synchronizer // ============================================================================ /** * Network Synchronizer * Handles offline-first synchronization with eventual coherence */ export class NetworkSynchronizer implements Serializable { id: string; nodeId: string; config: SyncConfig; // State state: SyncState; // Local and global memory fields localField: GlobalMemoryField | null; globalField: GlobalMemoryField | null; // Communication channel: PRRCChannel | null; phaseReference: PhaseReference | null; // Protocol dccProtocol: DCCProtocol | null; // Reconnection reconnectAttempts: i32; nextReconnectTime: i64; // Statistics totalSyncs: i32; successfulSyncs: i32; failedSyncs: i32; constructor(nodeId: string, config: SyncConfig = new SyncConfig()) { this.id = generateId("sync"); this.nodeId = nodeId; this.config = config; this.state = new SyncState(); this.localField = null; this.globalField = null; this.channel = null; this.phaseReference = null; this.dccProtocol = null; this.reconnectAttempts = 0; this.nextReconnectTime = 0; this.totalSyncs = 0; this.successfulSyncs = 0; this.failedSyncs = 0; } /** * Set the local memory field */ setLocalField(field: GlobalMemoryField): void { this.localField = field; } /** * Set the global memory field reference */ setGlobalField(field: GlobalMemoryField): void { this.globalField = field; } /** * Set the communication channel */ setChannel(channel: PRRCChannel): void { this.channel = channel; } /** * Set the DCC protocol */ setDCCProtocol(protocol: DCCProtocol): void { this.dccProtocol = protocol; } /** * Add a proposal to the log (for offline operation) */ addProposal(object: MemoryObject, proof: LocalProof, tickNumber: i64): ProposalLogEntry { const entry = new ProposalLogEntry(object, proof, tickNumber); this.state.proposalLog.push(entry); // Prune if too many if (this.state.proposalLog.length > this.config.offlineProposalLogSize) { // Remove oldest pending entries const toRemove: i32[] = []; for (let i = 0; i < this.state.proposalLog.length; i++) { if (this.state.proposalLog[i].status == "pending") { toRemove.push(i); if (toRemove.length >= 100) break; } } // Remove in reverse order for (let i = toRemove.length - 1; i >= 0; i--) { const idx = toRemove[i]; this.state.proposalLog.splice(idx, 1); } } return entry; } /** * Attempt to connect to the network * Step 1-2 of On Join protocol */ connect(): bool { if (this.channel === null) return false; this.state.connectionStatus = "connecting"; // Create phase reference for handshake this.phaseReference = new PhaseReference(this.channel!.channelPrimes.length); this.phaseReference!.nodeId = this.nodeId; // In real implementation, would handshake with remote node // For now, simulate successful connection this.state.connectionStatus = "connected"; this.state.lastConnectedTime = Date.now() as i64; this.reconnectAttempts = 0; return true; } /** * Disconnect from the network */ disconnect(): void { this.state.connectionStatus = "disconnected"; } /** * Check if connected */ isConnected(): bool { return this.state.connectionStatus == "connected" || this.state.connectionStatus == "syncing"; } /** * Pull deltas from global field * Step 3 of On Join / Step 1 of On Reconnect */ pullDeltas(): GMFDelta[] { if (this.globalField === null) return []; const deltas = this.globalField!.getDeltasSince(this.state.lastDeltaId); // Add to pending for (let i = 0; i < deltas.length; i++) { this.state.pendingDeltas.push(deltas[i]); } return deltas; } /** * Apply pending deltas to local field * Step 3 continued */ applyDeltas(): i32 { if (this.localField === null) return 0; let applied = 0; while (this.state.pendingDeltas.length > 0) { const delta = this.state.pendingDeltas.shift()!; if (delta.type == "add" && delta.object !== null) { // Add object to local field this.localField!.addObject(delta.object!, 0.5, 0.5); applied++; } else if (delta.type == "remove") { // Remove from local field this.localField!.removeObject(delta.objectId); applied++; } this.state.lastDeltaId = delta.id; this.state.appliedDeltaCount++; } return applied; } /** * Rebase local field against global * Step 4 of On Join - soft merge via resonance blending */ rebase(): i32 { if (this.localField === null || this.globalField === null) return 0; let merged = 0; const alpha = this.config.resonanceBlendAlpha; // For each global entry, blend with local const globalKeys = this.globalField!.entries.keys(); for (let i = 0; i < globalKeys.length; i++) { const globalEntry = this.globalField!.entries.get(globalKeys[i]); if (this.localField!.entries.has(globalKeys[i])) { // Entry exists locally - blend weights const localEntry = this.localField!.entries.get(globalKeys[i]); // Resonance blending of weights localEntry.weight.coherenceScore = (1 - alpha) * localEntry.weight.coherenceScore + alpha * globalEntry.weight.coherenceScore; localEntry.weight.redundancyScore = (1 - alpha) * localEntry.weight.redundancyScore + alpha * globalEntry.weight.redundancyScore; merged++; } } return merged; } /** * Submit pending proposals from log * Step 2 of On Reconnect */ submitPendingProposals(): i32 { if (this.dccProtocol === null || this.channel === null) return 0; let submitted = 0; for (let i = 0; i < this.state.proposalLog.length; i++) { const entry = this.state.proposalLog[i]; if (entry.status != "pending") continue; // Try to submit const proposal = this.dccProtocol!.propose(entry.object, entry.proof, this.nodeId); if (proposal !== null) { entry.status = "submitted"; entry.submissionAttempts++; entry.lastSubmissionTime = Date.now() as i64; submitted++; } } return submitted; } /** * Perform full synchronization */ sync(): SyncResult { const result = new SyncResult(); this.totalSyncs++; this.state.connectionStatus = "syncing"; // Step 1: Pull deltas const deltas = this.pullDeltas(); // Step 2: Apply deltas result.deltasApplied = this.applyDeltas(); // Step 3: Rebase local field const merged = this.rebase(); if (merged > 0) { result.conflictsResolved = merged; } // Step 4: Submit pending proposals if (this.isConnected()) { result.proposalsSubmitted = this.submitPendingProposals(); } // Update state this.state.lastSyncTime = Date.now() as i64; this.state.connectionStatus = "connected"; result.success = true; this.successfulSyncs++; return result; } /** * Attempt reconnection */ tryReconnect(): bool { const now = Date.now() as i64; if (now < this.nextReconnectTime) { return false; } if (this.reconnectAttempts >= this.config.maxReconnectAttempts) { return false; } this.reconnectAttempts++; const connected = this.connect(); if (!connected) { // Schedule next attempt this.nextReconnectTime = now + this.config.reconnectIntervalMs; this.failedSyncs++; return false; } return true; } /** * Main update loop - call periodically */ update(): SyncResult | null { // Check if we need to reconnect if (!this.isConnected() && this.config.autoReconnect) { if (!this.tryReconnect()) { return null; } } // If connected, sync if (this.isConnected()) { return this.sync(); } return null; } /** * Get synchronization statistics */ getStats(): SyncStats { const pendingProposals = this.state.proposalLog.filter( (e: ProposalLogEntry): bool => e.status == "pending" ).length; return new SyncStats( this.totalSyncs, this.successfulSyncs, this.failedSyncs, this.state.appliedDeltaCount, pendingProposals, this.isConnected() ); } /** * Reset synchronizer state */ reset(): void { this.state = new SyncState(); this.reconnectAttempts = 0; this.nextReconnectTime = 0; this.totalSyncs = 0; this.successfulSyncs = 0; this.failedSyncs = 0; } toJSON(): string { const builder = new JSONBuilder(); builder.startObject() .addStringField("id", this.id) .addStringField("nodeId", this.nodeId) .addStringField("connectionStatus", this.state.connectionStatus) .addNumberField("totalSyncs", f64(this.totalSyncs)) .addNumberField("successfulSyncs", f64(this.successfulSyncs)) .addNumberField("proposalLogSize", f64(this.state.proposalLog.length)) .endObject(); return builder.build(); } toString(): string { return `Synchronizer(${this.nodeId.substring(0, 8)}, ${this.state.connectionStatus})`; } } // ============================================================================ // Sync Statistics // ============================================================================ /** * Synchronization statistics */ export class SyncStats implements Serializable { totalSyncs: i32; successfulSyncs: i32; failedSyncs: i32; appliedDeltaCount: i32; pendingProposalCount: i32; isConnected: bool; constructor( totalSyncs: i32, successfulSyncs: i32, failedSyncs: i32, appliedDeltaCount: i32, pendingProposalCount: i32, isConnected: bool ) { this.totalSyncs = totalSyncs; this.successfulSyncs = successfulSyncs; this.failedSyncs = failedSyncs; this.appliedDeltaCount = appliedDeltaCount; this.pendingProposalCount = pendingProposalCount; this.isConnected = isConnected; } /** * Compute sync success rate */ successRate(): f64 { if (this.totalSyncs == 0) return 0; return f64(this.successfulSyncs) / f64(this.totalSyncs); } toJSON(): string { const builder = new JSONBuilder(); builder.startObject() .addNumberField("totalSyncs", f64(this.totalSyncs)) .addNumberField("successfulSyncs", f64(this.successfulSyncs)) .addNumberField("failedSyncs", f64(this.failedSyncs)) .addNumberField("appliedDeltaCount", f64(this.appliedDeltaCount)) .addNumberField("pendingProposalCount", f64(this.pendingProposalCount)) .addBooleanField("isConnected", this.isConnected) .addNumberField("successRate", this.successRate()) .endObject(); return builder.build(); } toString(): string { return `SyncStats(syncs=${this.successfulSyncs}/${this.totalSyncs})`; } } // ============================================================================ // Factory Functions // ============================================================================ /** * Create a network synchronizer */ export function createSynchronizer(nodeId: string): NetworkSynchronizer { return new NetworkSynchronizer(nodeId); } /** * Create a network synchronizer with custom config */ export function createSynchronizerWithConfig(nodeId: string, config: SyncConfig): NetworkSynchronizer { return new NetworkSynchronizer(nodeId, config); } /** * Create a sync configuration */ export function createSyncConfig(): SyncConfig { return new SyncConfig(); }