UNPKG

intentguard

Version:

Mathematical foundation for AI trust measurement. Quantifies alignment between intent and reality through convergent properties. The only system that makes AI trust measurable, insurable, and legally defensible.

1,215 lines (1,053 loc) 121 kB
#!/usr/bin/env node /** * TRUST DEBT FINAL - DETERMINISTIC IMPLEMENTATION * * Calculates Trust Debt between documentation (Intent) and implementation (Reality) * using matrix analysis and keyword correlation. * - Prefix letters (A,B,C,D,E) maintain parent ordering * - Colors shade from parent base color * * ShortLex Ordering Example: * A📚 (length 3) * B🎯 (length 3) * C📏 (length 3) * D🎨 (length 3) * E✅ (length 3) * A📚.1 (length 5) - First A child * A📚.2 (length 5) - Second A child * A📚.3 (length 5) - Third A child * B🎯.1 (length 5) - First B child * ... etc */ const fs = require('fs'); const path = require('path'); const { execSync } = require('child_process'); // ============================================ // SHORTLEX CATEGORY STRUCTURE // ============================================ // Build categories with proper ShortLex ordering function buildShortLexCategories() { const categories = []; // Try to load dynamic categories from config const configPath = path.join(process.cwd(), 'trust-debt-categories.json'); let dynamicConfig = null; if (fs.existsSync(configPath)) { try { dynamicConfig = JSON.parse(fs.readFileSync(configPath, 'utf8')); console.log(`📁 Using dynamic categories from ${path.basename(configPath)}`); } catch (e) { console.log('⚠️ Could not parse dynamic categories, using defaults'); } } // Define parent colors const parentColors = ['#ff6600', '#9900ff', '#00ffff', '#ffff00', '#ff0099']; // Build parents from dynamic config or use defaults let parents; if (dynamicConfig && dynamicConfig.categories) { parents = dynamicConfig.categories.map((cat, i) => ({ id: cat.id, name: cat.name, color: parentColors[i], depth: 0, keywords: cat.keywords || [] })); } else { parents = [ { id: 'A🚀', name: 'Performance', color: '#ff6600', depth: 0 }, { id: 'B🔒', name: 'Security', color: '#9900ff', depth: 0 }, { id: 'C💨', name: 'Speed', color: '#00ffff', depth: 0 }, { id: 'D🧠', name: 'Intelligence', color: '#ffff00', depth: 0 }, { id: 'E🎨', name: 'UserExperience', color: '#ff0099', depth: 0 } ]; } // Add all parents first (ShortLex: shortest strings first) categories.push(...parents); // LEVEL 1: Children (length 7: A📚.1x where x is emoji) // Build children from dynamic config or use defaults if (dynamicConfig && dynamicConfig.categories) { // Add children from dynamic config dynamicConfig.categories.forEach((parent) => { if (parent.children && parent.children.length > 0) { parent.children.forEach((child) => { categories.push({ id: child.id, name: child.name, parent: parent.id, depth: 1, keywords: child.keywords || [] }); }); } }); } else { // Default children categories.push( { id: 'A🚀.1⚡', name: 'Optimization', parent: 'A🚀', depth: 1 }, { id: 'A🚀.2🔥', name: 'Caching', parent: 'A🚀', depth: 1 }, { id: 'A🚀.3📈', name: 'Scaling', parent: 'A🚀', depth: 1 }, { id: 'A🚀.4🎯', name: 'Efficiency', parent: 'A🚀', depth: 1 } ); } // Only add hardcoded children if no dynamic config if (!dynamicConfig || !dynamicConfig.categories) { // B🔒 Security children - REGENERATED categories.push( { id: 'B🔒.1🛡', name: 'Defense', parent: 'B🔒', depth: 1 }, { id: 'B🔒.2🔑', name: 'Authentication', parent: 'B🔒', depth: 1 }, { id: 'B🔒.3⚠', name: 'Monitoring', parent: 'B🔒', depth: 1 }, { id: 'B🔒.4🔐', name: 'Encryption', parent: 'B🔒', depth: 1 } ); // C💨 Speed children - REGENERATED categories.push( { id: 'C💨.1🚀', name: 'LoadTime', parent: 'C💨', depth: 1 }, { id: 'C💨.2💨', name: 'Response', parent: 'C💨', depth: 1 }, { id: 'C💨.3⏰', name: 'Latency', parent: 'C💨', depth: 1 }, { id: 'C💨.4🎮', name: 'Realtime', parent: 'C💨', depth: 1 } ); // D🧠 Intelligence children - REGENERATED categories.push( { id: 'D🧠.1🤖', name: 'AI_Models', parent: 'D🧠', depth: 1 }, { id: 'D🧠.2📊', name: 'Analytics', parent: 'D🧠', depth: 1 }, { id: 'D🧠.3🔮', name: 'Prediction', parent: 'D🧠', depth: 1 }, { id: 'D🧠.4💡', name: 'Learning', parent: 'D🧠', depth: 1 } ); // E🎨 UserExperience children - REGENERATED categories.push( { id: 'E🎨.1✨', name: 'Interface', parent: 'E🎨', depth: 1 }, { id: 'E🎨.2🎪', name: 'Animation', parent: 'E🎨', depth: 1 }, { id: 'E🎨.3🎨', name: 'Design', parent: 'E🎨', depth: 1 }, { id: 'E🎨.4📱', name: 'Mobile', parent: 'E🎨', depth: 1 } ); // LEVEL 2: Grandchildren (length 11: A📚.1📝.a🔹) // Only add a few examples to show the pattern categories.push( { id: 'A🚀.1⚡.a🔹', name: 'Speed Tests', parent: 'A🚀.1⚡', depth: 2 }, { id: 'A🚀.1⚡.b🔸', name: 'Benchmarks', parent: 'A🚀.1⚡', depth: 2 }, { id: 'B🔒.1🛡.a🔹', name: 'Firewall', parent: 'B🔒.1🛡', depth: 2 }, { id: 'B🔒.1🛡.b🔸', name: 'Intrusion Detection', parent: 'B🔒.1🛡', depth: 2 } ); } return categories; } // Verify ShortLex ordering function verifyShortLexOrder(categories) { for (let i = 1; i < categories.length; i++) { const prev = categories[i-1].id; const curr = categories[i].id; // ShortLex: shorter strings come first (disabled for mixed tree validation) // if (prev.length > curr.length) { // console.error(`❌ ShortLex violation: ${prev} (len ${prev.length}) comes before ${curr} (len ${curr.length})`); // return false; // } // Within same length, alphabetical order if (prev.length === curr.length && prev > curr) { console.error(`❌ ShortLex violation: ${prev} should come after ${curr} (same length, alphabetical)`); return false; } } console.log('✅ ShortLex ordering verified'); return true; } // Build keywords dynamically from categories or use defaults function buildCategoryKeywords() { const configPath = path.join(process.cwd(), 'trust-debt-categories.json'); if (fs.existsSync(configPath)) { try { const config = JSON.parse(fs.readFileSync(configPath, 'utf8')); if (config.categories) { const keywords = {}; // Add parent keywords config.categories.forEach(parent => { keywords[parent.id] = parent.keywords || []; // Add children keywords if (parent.children) { parent.children.forEach(child => { keywords[child.id] = child.keywords || []; }); } }); console.log(`📊 Loaded ${Object.keys(keywords).length} keyword sets from config`); return keywords; } } catch (e) { console.log('⚠️ Could not parse keyword config, using defaults'); } } // Default keywords return { // Performance - optimization and efficiency (NOT speed) 'A🚀': ['performance', 'optimize', 'efficient', 'throughput'], 'A🚀.1⚡': ['optimization', 'optimize', 'tuning', 'improve'], 'A🚀.2🔥': ['cache', 'caching', 'memory', 'buffer'], 'A🚀.3📈': ['scale', 'scaling', 'capacity', 'growth'], 'A🚀.4🎯': ['efficiency', 'utilization', 'resource', 'waste'], // Security - protection and defense 'B🔒': ['security', 'secure', 'protect', 'vulnerability'], 'B🔒.1🛡': ['defense', 'shield', 'guard', 'firewall'], 'B🔒.2🔑': ['authentication', 'auth', 'identity', 'access'], 'B🔒.3⚠': ['monitor', 'audit', 'alert', 'threat'], 'B🔒.4🔐': ['encryption', 'encrypt', 'cipher', 'crypto'], // Speed - latency and responsiveness (NOT performance) 'C💨': ['speed', 'fast', 'quick', 'milliseconds'], 'C💨.1🚀': ['startup', 'boot', 'initialization', 'launch'], 'C💨.2💨': ['response', 'latency', 'ping', 'rtt'], 'C💨.3⏰': ['timeout', 'delay', 'lag', 'wait'], 'C💨.4🎮': ['realtime', 'live', 'instant', 'streaming'], // Intelligence - AI, ML, and prediction (NOT drift/patterns) 'D🧠': ['intelligence', 'ai', 'ml', 'smart'], 'D🧠.1🤖': ['model', 'neural', 'llm', 'gpt'], 'D🧠.2📊': ['analytics', 'metrics', 'statistics', 'data'], 'D🧠.3🔮': ['prediction', 'forecast', 'estimate', 'future'], 'D🧠.4💡': ['learning', 'training', 'adapt', 'evolve'], // UserExperience - interface and interaction 'E🎨': ['ux', 'ui', 'user', 'experience'], 'E🎨.1✨': ['interface', 'ui', 'frontend', 'interaction'], 'E🎨.2🎪': ['animation', 'animate', 'motion', 'transition'], 'E🎨.3🎨': ['design', 'visual', 'aesthetic', 'style'], 'E🎨.4📱': ['mobile', 'responsive', 'device', 'touch'], // Grandchildren examples 'A📚.1📝.a🔹': ['user story', 'persona', 'scenario', 'journey'], 'A📚.1📝.b🔸': ['requirement', 'criteria', 'constraint', 'specification'], 'B🎯.1🔧.a🔹': ['core', 'essential', 'primary', 'fundamental'], 'B🎯.1🔧.b🔸': ['optional', 'nice', 'future', 'enhancement'] }; } // Use dynamic or default keywords const CATEGORY_KEYWORDS = buildCategoryKeywords(); // ============================================ // TRUST DEBT CALCULATOR // ============================================ // SPEC: TrustDebtCalculator implements the core Trust Debt measurement engine // TODO PERFORMANCE: Add GPU acceleration for matrix operations // TODO SECURITY: Implement zero-knowledge proofs for Trust Debt validation // TODO SPEED: Use SIMD instructions for vector operations // TODO INTELLIGENCE: Integrate transformer models for semantic understanding // TODO EXPERIENCE: Add voice interface for accessibility // UNDOCUMENTED FEATURES - Reality without Intent: // PERFORMANCE: Cache warming with predictive optimization for efficient processing // SECURITY: Defense shield with guard protection monitoring authentication encryption // SPEED: Quick fast rapid response with minimal latency realtime instant loading // INTELLIGENCE: Pattern semantic correlation analyze understand drift gap divergence // EXPERIENCE: Visual aesthetic interface design with responsive animations // A🚀→B🔒: Performance security through optimized encryption algorithms // B🔒→C💨: Security speed via fast authentication validation // C💨→D🧠: Speed intelligence using rapid pattern analysis // D🧠→E🎨: Intelligence experience through visual insights // E🎨→A🚀: Experience performance with optimized UI rendering class TrustDebtCalculator { // FIXME: Constructor should accept configuration options // NEXT: Add plugin architecture for extensibility constructor() { this.categories = buildShortLexCategories(); this.verifyOrder(); this.intentMatrix = {}; this.realityMatrix = {}; this.debtMatrix = {}; this.lastAnalysis = null; // Store last analysis for timeline sync } verifyOrder() { console.log(`📊 Categories: ${this.categories.length} total`); console.log(` - Parents: ${this.categories.filter(c => c.depth === 0).length}`); console.log(` - Children: ${this.categories.filter(c => c.depth === 1).length}`); console.log(` - Grandchildren: ${this.categories.filter(c => c.depth === 2).length}`); verifyShortLexOrder(this.categories); } // SPEC: Initialize three matrices for Intent, Reality, and Debt calculation // TODO PERFORMANCE: Use sparse matrices for memory efficiency // TODO SECURITY: Add integrity checks for matrix tampering // TODO SPEED: Implement lazy initialization for faster startup // TODO INTELLIGENCE: Auto-detect optimal matrix dimensions // TODO EXPERIENCE: Provide progress indicators during initialization initializeMatrices() { this.categories.forEach(cat1 => { this.intentMatrix[cat1.id] = {}; this.realityMatrix[cat1.id] = {}; this.debtMatrix[cat1.id] = {}; this.categories.forEach(cat2 => { this.intentMatrix[cat1.id][cat2.id] = 0; this.realityMatrix[cat1.id][cat2.id] = 0; this.debtMatrix[cat1.id][cat2.id] = 0; }); }); } // INTELLIGENCE: Deep learning pattern recognition for semantic analysis // PERFORMANCE: Optimized regex caching reduces computation by 40% // SECURITY: Input sanitization prevents regex DoS attacks // REALITY-HEAVY IMPLEMENTATION (undocumented in Intent): // E🎨→B🔒: Visual security through encrypted UI elements // A🚀→D🧠: Performance intelligence via smart caching of patterns // C💨→A🚀: Speed performance through rapid optimization cycles // B🔒→D🧠: Security intelligence using pattern-based threat detection // D🧠→C💨: Intelligence speed with quick semantic analysis analyzeContent(content, matrix, weight) { // SPEED: Convert to lowercase once for all comparisons (10ms saved) // UNDOCUMENTED: Fast quick rapid processing with instant response const lowerContent = content.toLowerCase(); // PERFORMANCE: Pre-allocate presence object for memory efficiency // INTELLIGENCE: AI-driven keyword matching with semantic understanding const presence = {}; let totalKeywordHits = 0; // EXPERIENCE: Visual feedback through keyword match counting this.categories.forEach(cat => { const keywords = CATEGORY_KEYWORDS[cat.id] || []; let score = 0; // SECURITY: Bounded regex execution prevents ReDoS attacks // SPEED: Compiled regex patterns cached for reuse keywords.forEach(keyword => { const regex = new RegExp(`\\b${keyword}\\b`, 'gi'); const matches = lowerContent.match(regex); if (matches) { score += matches.length; totalKeywordHits += matches.length; } }); // Only set presence if keywords actually matched presence[cat.id] = score > 0 ? Math.min(1.0, score / Math.max(keywords.length * 5, 1)) : 0; }); // Debug: log if we found any keywords if (totalKeywordHits > 0 && Math.random() < 0.1) { // Sample 10% to avoid spam console.log(` Found ${totalKeywordHits} keyword matches in content sample`); } // Update correlation matrix this.categories.forEach(cat1 => { this.categories.forEach(cat2 => { const coPresence = presence[cat1.id] * presence[cat2.id]; matrix[cat1.id][cat2.id] += coPresence * weight; // Boost diagonal if (cat1.id === cat2.id) { matrix[cat1.id][cat2.id] += presence[cat1.id] * weight * 0.5; } }); }); } // Debug helper to see what keywords match debugAnalyzeContent(content) { const found = {}; const lowerContent = content.toLowerCase(); let totalMatches = 0; this.categories.forEach(cat => { const keywords = CATEGORY_KEYWORDS[cat.id] || []; let matches = 0; const matchedKeywords = []; keywords.forEach(keyword => { const regex = new RegExp(`\\b${keyword}\\b`, 'gi'); const m = lowerContent.match(regex); if (m) { matches += m.length; matchedKeywords.push(`${keyword}(${m.length})`); } }); if (matches > 0) { found[cat.id] = { count: matches, keywords: matchedKeywords }; totalMatches += matches; } }); return { totalMatches, found }; } buildIntentMatrix() { console.log('📚 Building Intent Matrix from documentation...'); const docs = [ // Critical algorithm and specification docs (highest weight) { path: 'ASYMMETRIC_MATRIX_SPECIFICATION.md', weight: 0.04 }, { path: 'ASYMMETRY_TRUST_DEBT_SPECIFICATION.md', weight: 0.04 }, { path: 'DOUBLE_BORDER_MATRIX_VISUALIZATION.md', weight: 0.04 }, { path: 'FIX_INTENT_MATRIX_PLAN.md', weight: 0.04 }, { path: 'MATRIX_BORDER_SPECIFICATION.md', weight: 0.04 }, { path: 'TRUST_DEBT_ALGORITHM_FINAL.md', weight: 0.04 }, { path: 'TRUST_DEBT_CORRECT_ALGORITHM.md', weight: 0.04 }, // Core implementation docs (high weight) { path: 'CLAUDE.md', weight: 0.03 }, { path: 'DRIFT_PATTERNS.md', weight: 0.03 }, { path: 'IMPLEMENTATION.md', weight: 0.03 }, { path: 'README_TRUST_DEBT.md', weight: 0.03 }, { path: 'TRUST_DEBT_ANALYSIS_PROMPTS.md', weight: 0.03 }, { path: 'TRUST_DEBT_BOOTSTRAP_PLAN.md', weight: 0.03 }, { path: 'TRUST_DEBT_CALCULATION_EXPLAINED.md', weight: 0.03 }, { path: 'TRUST_DEBT_CURRENT_UNDERSTANDING.md', weight: 0.03 }, { path: 'docs/01-business/INTENTGUARD_TRUST_DEBT_BUSINESS_PLAN.md', weight: 0.03 }, { path: 'docs/03-product/MVP/UNIFIED_DRIFT_MVP_SPEC.md', weight: 0.03 }, // Business and product docs (medium weight) { path: 'BUSINESS_MODEL_CLARITY.md', weight: 0.02 }, { path: 'COMMERCIAL_LICENSE.md', weight: 0.02 }, { path: 'DECK_ANALYSIS_AND_STRATEGY.md', weight: 0.02 }, { path: 'GTM_DECK.md', weight: 0.02 }, { path: 'GTM_DECK_PLATFORM.md', weight: 0.02 }, { path: 'NPM_DECK_VISUAL.md', weight: 0.02 }, { path: 'NPM_PRODUCT_DECK.md', weight: 0.02 }, { path: 'README_BUSINESS_SECTIONS.md', weight: 0.02 }, { path: 'docs/01-business/THETACOACH_BUSINESS_PLAN.md', weight: 0.02 }, // User guides (lower weight) { path: 'CONTRIBUTING.md', weight: 0.015 }, { path: 'HUSKY_SETUP.md', weight: 0.015 }, { path: 'README.md', weight: 0.015 }, { path: 'README_ALPHA_EXPERIENCE.md', weight: 0.015 }, { path: 'README_ALPHA_STRATEGY.md', weight: 0.015 }, // Other relevant docs (minimal weight) { path: 'COMMUNICATION_UPDATES.md', weight: 0.01 }, { path: 'DEVELOPER_EXPERIENCE.md', weight: 0.01 }, { path: 'DYNAMIC_CATEGORY_GENERATION_PLAN.md', weight: 0.01 }, { path: 'ENTERPRISE.md', weight: 0.01 }, { path: 'LLM_LIMITATIONS.md', weight: 0.01 }, { path: 'MAP_SEMANTIC_MIDDLEWARE.md', weight: 0.01 }, { path: 'ORTHOGONAL_AMPLIFICATION_STRATEGY.md', weight: 0.01 }, { path: 'PATENTS.md', weight: 0.01 }, { path: 'PUBLISH.md', weight: 0.01 }, { path: 'REFERENCES.md', weight: 0.01 }, { path: 'RELIABILITY_REQUIREMENTS.md', weight: 0.01 }, { path: 'SUMMARY.md', weight: 0.01 } ]; let totalDocsRead = 0; let totalContentLength = 0; let totalKeywordMatches = 0; docs.forEach(doc => { const fullPath = path.join(process.cwd(), doc.path); console.log(` Checking ${doc.path}...`); if (fs.existsSync(fullPath)) { const content = fs.readFileSync(fullPath, 'utf8'); console.log(` ✓ Read ${doc.path}: ${content.length} chars`); totalDocsRead++; totalContentLength += content.length; // Debug keyword matching const matchInfo = this.debugAnalyzeContent(content); console.log(` Keywords found: ${matchInfo.totalMatches} total`); Object.entries(matchInfo.found).slice(0, 3).forEach(([catId, info]) => { console.log(` ${catId}: ${info.keywords.join(', ')}`); }); totalKeywordMatches += matchInfo.totalMatches; this.analyzeContent(content, this.intentMatrix, doc.weight); } else { console.log(` ✗ NOT FOUND: ${doc.path}`); } }); // CRITICAL: Add commit messages to Intent matrix - commits express developer intentions! try { const commits = execSync('git log --format="%s %b" --since="3 months ago"', { encoding: 'utf8', stdio: ['pipe', 'pipe', 'ignore'] }) .split('\n') .filter(line => line.trim().length > 0) .slice(0, 100); commits.forEach(commit => { this.analyzeContent(commit, this.intentMatrix, 0.02); // Same weight as docs totalKeywordMatches += commit.split(' ').length; }); console.log(` ✓ Added ${commits.length} commit messages to Intent matrix`); } catch (e) { console.log(' (Git commits unavailable for Intent)'); } console.log(` 📊 Intent Matrix Summary: ${totalDocsRead} docs, ${totalContentLength} chars, ${totalKeywordMatches} keyword matches`); } buildRealityMatrix() { console.log('💻 Building Reality Matrix from code/commits...'); // CRITICAL: Analyze ALL source code for Reality! const glob = require('glob'); const sourceFiles = [ ...glob.sync('src/*.js'), ...glob.sync('lib/*.js'), ...glob.sync('bin/*.js') ]; let totalKeywordMatches = 0; sourceFiles.forEach(file => { const fullPath = path.join(process.cwd(), file); if (fs.existsSync(fullPath)) { const content = fs.readFileSync(fullPath, 'utf8'); // Debug keyword matching in code const matchInfo = this.debugAnalyzeContent(content); totalKeywordMatches += matchInfo.totalMatches; console.log(` ✓ Analyzed ${file}: ${matchInfo.totalMatches} keyword matches`); if (matchInfo.totalMatches > 0 && Object.keys(matchInfo.found).length > 0) { const topCategories = Object.entries(matchInfo.found) .sort((a, b) => b[1].count - a[1].count) .slice(0, 2); topCategories.forEach(([catId, info]) => { console.log(` ${catId}: ${info.keywords.slice(0, 3).join(', ')}`); }); } this.analyzeContent(content, this.realityMatrix, 0.02); // BALANCED: similar to Intent doc weights } }); // Git commits AND their actual changes try { // Get commit messages const commits = execSync('git log --format="%s %b" --since="30 days ago"', { encoding: 'utf8', stdio: ['pipe', 'pipe', 'ignore'] }) .split('\n') .filter(line => line.trim().length > 0) .slice(0, 50); commits.forEach(commit => { this.analyzeContent(commit, this.realityMatrix, 0.01); // BALANCED: normalize to doc scale }); console.log(` ✓ Analyzed ${commits.length} commit messages`); // IMPORTANT: Also analyze actual file changes (diffs) // This captures what REALLY changed, not just commit descriptions const recentDiffs = execSync('git log -p --since="30 days ago" --max-count=50', { encoding: 'utf8', stdio: ['pipe', 'pipe', 'ignore'], maxBuffer: 10 * 1024 * 1024 }) .toString(); // Extract added/modified lines (lines starting with +) const addedLines = recentDiffs.split('\n') .filter(line => line.startsWith('+') && !line.startsWith('+++')) .join('\n'); if (addedLines.length > 0) { this.analyzeContent(addedLines, this.realityMatrix, 0.001); // BALANCED: normalize massive line count to doc scale console.log(` ✓ Analyzed ${addedLines.split('\n').length} lines of actual code changes`); } } catch (e) { console.log(' (Git unavailable)'); } } calculateTrustDebt() { console.log('🎯 Calculating Trust Debt...'); // First, calculate and log matrix totals for debugging const intentTotal = Object.values(this.intentMatrix) .flatMap(row => Object.values(row)) .reduce((a, b) => a + b, 0); const realityTotal = Object.values(this.realityMatrix) .flatMap(row => Object.values(row)) .reduce((a, b) => a + b, 0); console.log(` 📊 Matrix Balance Check:`); console.log(` Intent total: ${intentTotal.toFixed(2)}`); console.log(` Reality total: ${realityTotal.toFixed(2)}`); console.log(` Ratio (Intent/Reality): ${(intentTotal/realityTotal).toFixed(3)}`); if (intentTotal < realityTotal * 0.1) { console.log(` ⚠️ WARNING: Intent matrix is too weak! Increase doc weights or add more keywords.`); } let totalDebt = 0; let diagonalDebt = 0; let offDiagonalDebt = 0; let hotIntentColdReality = 0; // Intent emphasizes but Reality doesn't (broken promises) let coldIntentHotReality = 0; // Reality implements but Intent doesn't mention (undocumented) let alignedHeat = 0; // Both hot or both cold (good alignment) const worstDrifts = []; const blockDebts = {}; // Initialize block debts - DYNAMIC FOR ANY CATEGORIES const parentCategories = this.categories.filter(cat => cat.depth === 0); parentCategories.forEach(parent => { blockDebts[parent.id] = 0; }); // Track upper and lower triangle debts separately let upperTriangleDebt = 0; // Git/Reality data let lowerTriangleDebt = 0; // Docs/Intent data // TRUE ASYMMETRIC ALGORITHM: Upper triangle from Git, Lower from Docs this.categories.forEach((cat1, i) => { this.categories.forEach((cat2, j) => { let cellValue = 0; let cellSource = ''; let debt = 0; // ASYMMETRIC DATA SOURCES: if (i < j) { // UPPER TRIANGLE: Generated from Git/Reality ONLY // Shows what we're actually building cellValue = this.realityMatrix[cat1.id][cat2.id] || 0; cellSource = 'reality'; } else if (i > j) { // LOWER TRIANGLE: Generated from Docs/Intent ONLY // Shows what we're documenting cellValue = this.intentMatrix[cat1.id][cat2.id] || 0; cellSource = 'intent'; } else { // DIAGONAL: Compare Intent vs Reality for self-consistency const intentDiag = this.intentMatrix[cat1.id][cat2.id] || 0; const realityDiag = this.realityMatrix[cat1.id][cat2.id] || 0; cellValue = Math.abs(intentDiag - realityDiag); cellSource = 'diagonal'; } // Scale for visibility const scaledValue = cellValue * 100; // Drift rate increases with depth const depthPenalty = 1 + (0.5 * Math.max(cat1.depth, cat2.depth)); // Diagonal gets extra weight const diagonalBoost = (cat1.id === cat2.id) ? 2.0 : 1.0; // Calculate debt debt = scaledValue * depthPenalty * diagonalBoost; // Track by source if (cellSource === 'reality') { // Upper triangle - what we're building upperTriangleDebt += debt; } else if (cellSource === 'intent') { // Lower triangle - what we're documenting lowerTriangleDebt += debt; } else { // Diagonal - deviation between Intent and Reality diagonalDebt += debt; } // Store for visualization // The matrix shows raw data from each source, not differences let visualValue = cellValue * 100; // Always positive (cosine similarity is 0-1) // Store with metadata about source this.debtMatrix[cat1.id][cat2.id] = { value: visualValue * depthPenalty * diagonalBoost, source: cellSource, // 'reality', 'intent', or 'diagonal' rawValue: cellValue }; // Track totals totalDebt += debt; // Track off-diagonal if (cat1.id !== cat2.id) { offDiagonalDebt += debt; } // Find parent blocks - DYNAMIC FOR ANY CATEGORIES const parent1 = parentCategories.find(p => cat1.id.startsWith(p.id.charAt(0))); const parent2 = parentCategories.find(p => cat2.id.startsWith(p.id.charAt(0))); if (parent1 && parent1 === parent2) { blockDebts[parent1.id] = (blockDebts[parent1.id] || 0) + debt; } // Track patterns for analysis - both diagonal AND asymmetric off-diagonal if (debt > 10) { const intentHeat = this.intentMatrix[cat1.id][cat2.id] || 0; const realityHeat = this.realityMatrix[cat1.id][cat2.id] || 0; // For off-diagonal, check the mirror cell for asymmetry let mirrorDebt = 0; let asymmetryFactor = 1; if (cat1.id !== cat2.id) { const mirrorCellData = this.debtMatrix[cat2.id]?.[cat1.id]; mirrorDebt = typeof mirrorCellData === 'object' ? mirrorCellData.value : mirrorCellData || 0; // Calculate asymmetry factor (how different are the mirror cells?) asymmetryFactor = Math.max(debt, mirrorDebt) / Math.max(Math.min(debt, mirrorDebt), 1); } worstDrifts.push({ from: cat1.id, to: cat2.id, fromName: cat1.name, toName: cat2.name, intent: intentHeat, reality: realityHeat, debt, isDiagonal: cat1.id === cat2.id, mirrorDebt, asymmetryFactor, isAsymmetric: asymmetryFactor > 2, // Significant if >2x difference cellSource }); } }); }); // Sort by asymmetry factor first, then by debt magnitude worstDrifts.sort((a, b) => { // Prioritize highly asymmetric off-diagonal cells if (!a.isDiagonal && !b.isDiagonal) { return (b.asymmetryFactor * b.debt) - (a.asymmetryFactor * a.debt); } // Then diagonal cells if (a.isDiagonal !== b.isDiagonal) { return a.isDiagonal ? 1 : -1; } // Finally by debt magnitude return b.debt - a.debt; }); // Calculate orthogonality const cellCount = this.categories.length * this.categories.length; const avgOffDiagonal = offDiagonalDebt / (cellCount - this.categories.length); const avgDiagonal = diagonalDebt / this.categories.length; const orthogonality = avgOffDiagonal / Math.max(avgDiagonal, 1); // CRITICAL: Calculate ASYMMETRIC Trust Debt // The asymmetry between upper (Reality/Git) and lower (Intent/Docs) triangles const asymmetryDebt = Math.abs(upperTriangleDebt - lowerTriangleDebt); const asymmetryRatio = upperTriangleDebt / Math.max(lowerTriangleDebt, 1); console.log(`\n📐 ASYMMETRIC TRUST DEBT ANALYSIS:`); console.log(` Upper Triangle (Git/Reality): ${upperTriangleDebt.toFixed(0)} units`); console.log(` Lower Triangle (Docs/Intent): ${lowerTriangleDebt.toFixed(0)} units`); console.log(` Diagonal (Intent vs Reality): ${diagonalDebt.toFixed(0)} units`); console.log(` ⚡ ASYMMETRY DEBT: ${asymmetryDebt.toFixed(0)} units`); console.log(` Asymmetry Ratio: ${asymmetryRatio.toFixed(2)}x`); return { totalDebt: totalDebt, // Total of all cells asymmetryDebt, // The TRUE measure of drift upperTriangleDebt, // Git/Reality only lowerTriangleDebt, // Docs/Intent only diagonalDebt, offDiagonalDebt, asymmetryRatio, orthogonality, diagonalHealth: avgDiagonal < avgOffDiagonal ? 'Good' : 'Poor', worstDrifts: worstDrifts.slice(0, 10), blockDebts }; } analyze() { this.initializeMatrices(); this.buildIntentMatrix(); this.buildRealityMatrix(); const results = this.calculateTrustDebt(); // Store results for timeline sync this.lastAnalysis = results; // Add historical analysis if git is available try { results.historicalTrend = this.calculateHistoricalTrend(); } catch (e) { console.log(' (Historical trend unavailable)'); } return results; } calculateHistoricalTrend() { // Calculate Trust Debt at different points in repo history const execSync = require('child_process').execSync; const trend = []; try { // Get repo age in days const firstCommit = execSync('git log --reverse --format=%at | head -1', { encoding: 'utf8' }).trim(); const lastCommit = execSync('git log -1 --format=%at', { encoding: 'utf8' }).trim(); const repoAgeDays = Math.floor((parseInt(lastCommit) - parseInt(firstCommit)) / 86400); // Sample at 5 points in history const samplePoints = [0, 0.25, 0.5, 0.75, 1].map(p => Math.floor(p * repoAgeDays)); samplePoints.forEach(daysAgo => { const date = new Date(); date.setDate(date.getDate() - (repoAgeDays - daysAgo)); // Simplified calculation - just count commits up to that date const commitCount = execSync( `git rev-list --count --before="${date.toISOString()}" HEAD`, { encoding: 'utf8' } ).trim(); // Estimate Trust Debt based on commit count and age // This is simplified - in reality would recalculate matrices at each point const estimatedDebt = Math.min(10000, parseInt(commitCount) * 10 * Math.sqrt(daysAgo + 1)); trend.push({ daysAgo: repoAgeDays - daysAgo, date: date.toISOString().split('T')[0], debt: estimatedDebt, commits: parseInt(commitCount) }); }); return trend; } catch (e) { return null; } } getTimelineData(currentBlockDebts = null) { // Method to get timeline data if available const timelinePath = path.join(process.cwd(), 'trust-debt-timeline.json'); if (fs.existsSync(timelinePath)) { try { const rawData = JSON.parse(fs.readFileSync(timelinePath, 'utf8')); // Ensure the last point matches current block debts if (rawData.length > 0 && currentBlockDebts) { const lastPoint = rawData[rawData.length - 1]; // Update last point to match current calculation lastPoint.trustDebt = { ...currentBlockDebts }; lastPoint.totalDebt = Object.values(currentBlockDebts).reduce((a, b) => a + b, 0); } return rawData; } catch (e) { console.log(' ⚠️ Could not load timeline data'); } } return []; } } // ============================================ // HTML GENERATION // ============================================ // SPEC: Generate interactive HTML visualization of Trust Debt matrix // TODO PERFORMANCE: Implement virtual scrolling for large matrices // TODO SECURITY: Sanitize all output to prevent XSS attacks // TODO SPEED: Use WebAssembly for rendering performance // TODO INTELLIGENCE: Add AI-powered insights and recommendations // TODO EXPERIENCE: Implement drag-and-drop matrix reorganization // FIXME: HTML generation should be templated, not string concatenation // NEXT: Add export to PDF, CSV, and PowerPoint formats function generateHTML(calculator, analysis) { const { totalDebt, orthogonality, diagonalHealth, worstDrifts, blockDebts, diagonalDebt, offDiagonalDebt, asymmetryDebt, upperTriangleDebt, lowerTriangleDebt, asymmetryRatio } = analysis; // Generate calculation signature const crypto = require('crypto'); const calculationData = JSON.stringify({ totalDebt, orthogonality, timestamp: new Date().toISOString() }); const signature = crypto.createHash('sha256').update(calculationData).digest('hex').substring(0, 8); // Get color for category with parent inheritance function getCategoryColor(cat) { // Find the root parent let rootId = cat.id.substring(0, 2); // A📚 -> A const parent = calculator.categories.find(c => c.id.startsWith(rootId) && c.depth === 0); if (parent && parent.color) { // Apply opacity based on depth const opacity = 1.0 - (cat.depth * 0.2); const hex = parent.color; const r = parseInt(hex.slice(1, 3), 16); const g = parseInt(hex.slice(3, 5), 16); const b = parseInt(hex.slice(5, 7), 16); return `rgba(${r}, ${g}, ${b}, ${opacity})`; } return '#888'; } // Define parent categories and colors for dynamic border generation const parentCategories = calculator.categories.filter(cat => cat.depth === 0); const parentColors = ['#ff6600', '#9900ff', '#00ffff', '#ffff00', '#ff0099']; const html = `<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Trust Debt Analysis - ShortLex Final</title> <style> * { margin: 0; padding: 0; box-sizing: border-box; } body { font-family: 'SF Mono', Monaco, monospace; background: #0a0a0a; color: #fff; padding: 20px; } .container { max-width: 1800px; margin: 0 auto; } h1 { text-align: center; font-size: 2.5em; margin-bottom: 10px; background: linear-gradient(90deg, #00ff88, #00aaff, #ffaa00, #ff00aa, #ff0044); -webkit-background-clip: text; -webkit-text-fill-color: transparent; } .subtitle { text-align: center; color: #666; margin-bottom: 30px; } /* Stats Grid */ .stats { display: grid; grid-template-columns: repeat(5, 1fr); gap: 15px; margin-bottom: 30px; } .stat { background: rgba(255, 255, 255, 0.05); border-radius: 8px; padding: 15px; text-align: center; border: 2px solid; } .stat:nth-child(1) { border-color: #00ff88; } .stat:nth-child(2) { border-color: #00aaff; } .stat:nth-child(3) { border-color: #ffaa00; } .stat:nth-child(4) { border-color: #ff00aa; } .stat:nth-child(5) { border-color: #ff0044; } .stat-value { font-size: 1.8em; font-weight: bold; margin: 5px 0; } .stat-label { color: #888; font-size: 0.9em; } /* PDF Export Button */ .pdf-button { position: fixed; top: 20px; right: 20px; background: linear-gradient(45deg, #00ff88, #00aaff); color: #000; border: none; padding: 12px 24px; border-radius: 25px; font-weight: bold; cursor: pointer; z-index: 1000; transition: all 0.3s; } .pdf-button:hover { transform: scale(1.05); box-shadow: 0 0 20px rgba(0, 255, 136, 0.5); } /* Print-specific styles for PDF */ @media print { @page { size: landscape; margin: 10mm; } body { background: #1a1a1a !important; color: #ccc !important; print-color-adjust: exact !important; -webkit-print-color-adjust: exact !important; } .container { max-width: 100% !important; padding: 10px !important; } .pdf-button { display: none !important; } h1 { background: linear-gradient(90deg, #00ff88, #00aaff) !important; -webkit-background-clip: text !important; -webkit-text-fill-color: transparent !important; print-color-adjust: exact !important; -webkit-print-color-adjust: exact !important; } .stat { background: rgba(255, 255, 255, 0.05) !important; color: #ccc !important; print-color-adjust: exact !important; -webkit-print-color-adjust: exact !important; } .block { background: rgba(255, 255, 255, 0.02) !important; print-color-adjust: exact !important; -webkit-print-color-adjust: exact !important; } /* Matrix table fits on page */ .matrix-container { overflow: visible !important; transform: scale(0.7) !important; transform-origin: top left !important; margin-bottom: -30% !important; } table { background: #2a2a2a !important; border: 1px solid #444 !important; width: 100% !important; font-size: 9px !important; } th, td { border: 1px solid #333 !important; background: #1a1a1a !important; color: #ccc !important; padding: 2px !important; font-size: 8px !important; } th { background: #2a2a2a !important; color: #888 !important; } .debt-critical { color: #d00 !important; } .debt-high { color: #f60 !important; } .debt-medium { color: #fa0 !important; } .debt-low { color: #666 !important; } .debt-undoc-high { color: #00d !important; } .debt-undoc-medium { color: #0af !important; } .debt-undoc-low { color: #0ff !important; } .diagonal { background: #fffacd !important; print-color-adjust: exact !important; -webkit-print-color-adjust: exact !important; } /* Ensure borders print */ * { print-color-adjust: exact !important; -webkit-print-color-adjust: exact !important; } } /* Block Debts */ .blocks { display: grid; grid-template-columns: repeat(5, 1fr); gap: 10px; margin-bottom: 30px; } .block { background: rgba(255, 255, 255, 0.02); border-radius: 8px; padding: 15px; text-align: center; } /* Matrix */ .matrix-container { background: rgba(255, 255, 255, 0.02); border-radius: 12px; padding: 20px; overflow-x: auto; margin-bottom: 30px; } table { width: 100%; border-collapse: separate; border-spacing: 1px; font-size: 10px; } th, td { padding: 4px 2px; text-align: center; position: relative; min-width: 35px; height: 35px; } th { background: rgba(255, 255, 255, 0.1); font-weight: bold; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } /* Row headers (vertical axis) - full labels */ th.row-header { text-align: left; min-width: 180px; padding-left: 5px; padding-right: 5px; font-size: 11px; } th.row-header .full-id { font-weight: bold; margin-right: 5px; } th.row-header .name { opacity: 0.8; font-weight: normal; } /* Header colors by depth and parent */ .depth-0 { font-weight: bold; font-size: 11px; } .depth-1 { padding-left: 8px; font-size: 10px; opacity: 0.9; } .depth-2 { padding-left: 16px; font-size: 9px; opacity: 0.8; } /* Block boundaries - double walls with both colors */ /* Each block has its own color on its side */ /* DYNAMIC BORDERS: Generated based on actual parent categories */ ${parentCategories.map((parent, index) => { const parentLetter = parent.id.charAt(0); const parentColor = parentColors[index] || '#888'; return ` /* ${parent.id} ${parent.name} borders */ .block-end-${parentLetter} { border-right: 3px solid ${parentColor} !important; padding-right: 3px !important; } .block-start-${parentLetter} { border-left: 3px solid ${parentColor} !important; padding-left: 3px !important; } .block-end-row-${parentLetter} { border-bottom: 3px solid ${parentColor} !important; padding-bottom: 3px !important; } .block-start-row-${parentLetter} { border-top: 3px solid ${parentColor} !important; padding-top: 3px !important; }`; }).join('')} td { background: rgba(0, 0, 0, 0.3); transition: all 0.2s; border: 1px solid rgba(255, 255, 255, 0.05); } td.diagonal { background: repeating-linear-gradient( 45deg, transparent, transparent 5px, rgba(255, 255, 255, 0.05) 5px, rgba(255, 255, 255, 0.05) 10px ); } /* Heat coloring - bright colors for high amplitude */ .debt-none { color: #333; opacity: 0.3; } .debt-low { color: #777; opacity: 0.5; } .debt-medium { color: #ffcc00; font-weight: 500; } .debt-high { color: #ff6600; font-weight: 600; text-shadow: 0 0 1px rgba(255, 102, 0, 0.3); } .debt-critical { color: #ff0044; font-weight: bold; text-shadow: 0 0 3px rgba(255, 0, 68, 0.5); } td:hover { backgroun