/** * Framework Activity Timeline * Tractatus Framework - Phase 3: Data Visualization * * Visual timeline showing framework component interactions * Color-coded by service */ class ActivityTimeline { constructor(containerId) { this.container = document.getElementById(containerId); if (!this.container) { console.error(`[ActivityTimeline] Container #${containerId} not found`); return; } this.currentPath = 'fast'; // Default to fast path // Define three execution paths with realistic timings this.pathProfiles = { fast: { name: 'Fast Path', description: 'Simple request, all checks pass', totalTime: '65ms', events: [ { time: '0ms', timeMs: 0, service: 'instruction', name: 'InstructionPersistence', action: 'Load cached instructions', color: '#4338ca' }, { time: '5ms', timeMs: 5, service: 'validator', name: 'CrossReferenceValidator', action: 'Quick validation check', color: '#6d28d9' }, { time: '15ms', timeMs: 15, service: 'boundary', name: 'BoundaryEnforcer', action: 'Auto-approved operation', color: '#047857' }, { time: '25ms', timeMs: 25, service: 'pressure', name: 'ContextPressureMonitor', action: 'Normal pressure detected', color: '#b45309' }, { time: '50ms', timeMs: 50, service: 'validator', name: 'CrossReferenceValidator', action: 'Final validation', color: '#6d28d9' }, { time: '65ms', timeMs: 65, service: 'pressure', name: 'ContextPressureMonitor', action: 'Update metrics', color: '#b45309' } ] }, standard: { name: 'Standard Path', description: 'Needs validation and verification', totalTime: '135ms', events: [ { time: '0ms', timeMs: 0, service: 'instruction', name: 'InstructionPersistence', action: 'Load HIGH persistence instructions', color: '#4338ca' }, { time: '8ms', timeMs: 8, service: 'validator', name: 'CrossReferenceValidator', action: 'Verify against instruction history', color: '#6d28d9' }, { time: '30ms', timeMs: 30, service: 'boundary', name: 'BoundaryEnforcer', action: 'Check approval requirements', color: '#047857' }, { time: '55ms', timeMs: 55, service: 'pressure', name: 'ContextPressureMonitor', action: 'Calculate pressure level', color: '#b45309' }, { time: '95ms', timeMs: 95, service: 'metacognitive', name: 'MetacognitiveVerifier', action: 'Verify operation alignment', color: '#be185d' }, { time: '120ms', timeMs: 120, service: 'validator', name: 'CrossReferenceValidator', action: 'Final validation check', color: '#6d28d9' }, { time: '135ms', timeMs: 135, service: 'pressure', name: 'ContextPressureMonitor', action: 'Update pressure metrics', color: '#b45309' } ] }, complex: { name: 'Complex Path', description: 'Requires deliberation and consensus', totalTime: '285ms', events: [ { time: '0ms', timeMs: 0, service: 'instruction', name: 'InstructionPersistence', action: 'Load HIGH persistence instructions', color: '#4338ca' }, { time: '8ms', timeMs: 8, service: 'validator', name: 'CrossReferenceValidator', action: 'Verify request against instruction history', color: '#6d28d9' }, { time: '35ms', timeMs: 35, service: 'boundary', name: 'BoundaryEnforcer', action: 'Check if request requires human approval', color: '#047857' }, { time: '60ms', timeMs: 60, service: 'pressure', name: 'ContextPressureMonitor', action: 'Calculate current pressure level', color: '#b45309' }, { time: '105ms', timeMs: 105, service: 'metacognitive', name: 'MetacognitiveVerifier', action: 'Verify operation alignment', color: '#be185d' }, { time: '160ms', timeMs: 160, service: 'deliberation', name: 'PluralisticDeliberation', action: 'Coordinate stakeholder perspectives', color: '#0f766e' }, { time: '255ms', timeMs: 255, service: 'validator', name: 'CrossReferenceValidator', action: 'Final validation check', color: '#6d28d9' }, { time: '285ms', timeMs: 285, service: 'pressure', name: 'ContextPressureMonitor', action: 'Update pressure metrics', color: '#b45309' } ] } }; // Initialize with fast path by default this.events = this.pathProfiles[this.currentPath].events; this.init(); } init() { this.render(); this.isSimulating = false; console.log('[ActivityTimeline] Initialized'); } render() { const eventsHTML = this.events.map((event, index) => `
${event.time}
${event.name}
${event.action}
`).join(''); const currentProfile = this.pathProfiles[this.currentPath]; this.container.innerHTML = `

Governance Flow

Estimated timing based on current performance data

Execution Path:
${currentProfile.description}

This shows the framework's governance components working together to validate and process each request. Each component has a specific role in ensuring safe, values-aligned AI operation.

Note: Timing values are estimates based on current performance statistics and may vary in production.

${eventsHTML}
Total processing time: ${currentProfile.totalTime} | All services coordinated
`; // Apply colors via JavaScript (CSP-compliant) this.applyColors(); // Attach event listeners to path radio buttons this.attachPathListeners(); } attachPathListeners() { const radios = this.container.querySelectorAll('.path-radio'); radios.forEach(radio => { radio.addEventListener('change', (e) => { this.setPath(e.target.value); }); }); } setPath(pathName) { if (!this.pathProfiles[pathName]) { console.error(`[ActivityTimeline] Unknown path: ${pathName}`); return; } console.log(`[ActivityTimeline] Switching to ${pathName} path`); this.currentPath = pathName; this.events = this.pathProfiles[pathName].events; this.render(); } applyColors() { document.querySelectorAll('.service-dot').forEach(dot => { const color = dot.getAttribute('data-color'); dot.style.backgroundColor = color; }); document.querySelectorAll('.service-name').forEach(name => { const color = name.getAttribute('data-color'); name.style.color = color; }); } activateEvent(index) { const eventElement = this.container.querySelector(`[data-event-index="${index}"]`); if (!eventElement) return; const event = this.events[index]; // Highlight the event card eventElement.style.borderColor = event.color; eventElement.style.backgroundColor = `${event.color}10`; // 10% opacity eventElement.style.boxShadow = `0 4px 12px ${event.color}40`; // Enlarge and pulse the service dot const dot = eventElement.querySelector('.service-dot'); if (dot) { dot.style.width = '12px'; dot.style.height = '12px'; dot.style.boxShadow = `0 0 8px ${event.color}`; } console.log(`[ActivityTimeline] Activated event ${index}: ${event.name}`); } deactivateEvent(index) { const eventElement = this.container.querySelector(`[data-event-index="${index}"]`); if (!eventElement) return; // Reset to default styling eventElement.style.borderColor = '#e5e7eb'; eventElement.style.backgroundColor = '#ffffff'; eventElement.style.boxShadow = ''; // Reset service dot const dot = eventElement.querySelector('.service-dot'); if (dot) { dot.style.width = '12px'; dot.style.height = '12px'; dot.style.boxShadow = ''; } } async simulateFlow() { if (this.isSimulating) { console.log('[ActivityTimeline] Already simulating, ignoring request'); return; } this.isSimulating = true; console.log('[ActivityTimeline] Starting governance flow simulation'); // Reset all events first for (let i = 0; i < this.events.length; i++) { this.deactivateEvent(i); } // Simulate each event activation with realistic timing for (let i = 0; i < this.events.length; i++) { const event = this.events[i]; const prevEvent = i > 0 ? this.events[i - 1] : null; // Calculate actual delay based on event timing (scaled 2x for visibility) const delay = prevEvent ? (event.timeMs - prevEvent.timeMs) * 2 : 0; await new Promise(resolve => setTimeout(resolve, delay)); // Deactivate previous event if (i > 0) { this.deactivateEvent(i - 1); } // Activate current event this.activateEvent(i); console.log(`[ActivityTimeline] Event ${i} activated at ${event.time} (delay: ${delay}ms)`); } // Keep the last event active for a moment, then deactivate await new Promise(resolve => setTimeout(resolve, 800)); this.deactivateEvent(this.events.length - 1); this.isSimulating = false; console.log('[ActivityTimeline] Governance flow simulation complete'); } reset() { console.log('[ActivityTimeline] Resetting timeline'); for (let i = 0; i < this.events.length; i++) { this.deactivateEvent(i); } this.isSimulating = false; } } // Auto-initialize if container exists if (typeof window !== 'undefined') { function initActivityTimeline() { console.log('[ActivityTimeline] Attempting to initialize, readyState:', document.readyState); const container = document.getElementById('activity-timeline'); if (container) { console.log('[ActivityTimeline] Container found, creating instance'); window.activityTimeline = new ActivityTimeline('activity-timeline'); } else { console.error('[ActivityTimeline] Container #activity-timeline not found in DOM'); } } // Initialize immediately if DOM is already loaded, otherwise wait for DOMContentLoaded console.log('[ActivityTimeline] Script loaded, readyState:', document.readyState); if (document.readyState === 'loading') { console.log('[ActivityTimeline] Waiting for DOMContentLoaded'); document.addEventListener('DOMContentLoaded', initActivityTimeline); } else { console.log('[ActivityTimeline] DOM already loaded, initializing immediately'); initActivityTimeline(); } } // Export for module systems if (typeof module !== 'undefined' && module.exports) { module.exports = ActivityTimeline; }