UNPKG

claude-code-collective

Version:

Sub-agent collective framework for Claude Code with TDD validation, hub-spoke coordination, and automated handoffs

881 lines (747 loc) 30.4 kB
const MetricsCollector = require('./MetricsCollector'); /** * TDDHandoffMetrics - Hypothesis 3 Validation * * Tests the hypothesis that Test-Driven Development handoffs improve quality * and reduce errors compared to traditional handoff methods. * * Key Metrics: * - Handoff success rate >80% * - Test coverage >95% for agent transitions * - 50% reduction in handoff failures * - Improved error detection and contract validation */ class TDDHandoffMetrics extends MetricsCollector { constructor(options = {}) { super(options); this.hypothesis = 'h3_tddHandoffs'; this.handoffEvents = []; this.testResults = []; this.contractValidations = []; this.qualityMetrics = []; // TDD-specific configuration this.tddConfig = { targetSuccessRate: 0.8, // 80% targetTestCoverage: 0.95, // 95% targetErrorReduction: 0.5, // 50% maxHandoffTime: 30000, // 30 seconds ...options.tddConfig }; // Contract and handoff tracking this.contractDefinitions = new Map(); this.handoffChains = new Map(); this.qualityGates = new Map(); } /** * Record handoff initiation */ async recordHandoffStart(data) { const handoffEvent = { handoffId: data.handoffId || this.generateId(), fromAgent: data.fromAgent, toAgent: data.toAgent, taskType: data.taskType, startTime: data.startTime || Date.now(), hasContract: data.hasContract !== false, contractId: data.contractId, context: data.context || {}, expectedOutcome: data.expectedOutcome, priority: data.priority || 'normal', metadata: data.metadata || {} }; this.handoffEvents.push(handoffEvent); // Initialize handoff chain tracking this.updateHandoffChain(handoffEvent); await this.store('handoff_start', handoffEvent, { hypothesis: this.hypothesis, experiment: data.experiment || 'default' }); return handoffEvent.handoffId; } /** * Record handoff completion */ async recordHandoffCompletion(data) { const completionEvent = { handoffId: data.handoffId, endTime: data.endTime || Date.now(), success: data.success !== false, outcome: data.outcome, errors: data.errors || [], testResults: data.testResults || {}, validationResults: data.validationResults || {}, qualityScore: data.qualityScore || 0, retryCount: data.retryCount || 0 }; // Find matching handoff start event const handoffStart = this.handoffEvents.find(h => h.handoffId === data.handoffId); if (handoffStart) { completionEvent.duration = completionEvent.endTime - handoffStart.startTime; completionEvent.fromAgent = handoffStart.fromAgent; completionEvent.toAgent = handoffStart.toAgent; completionEvent.taskType = handoffStart.taskType; completionEvent.hasContract = handoffStart.hasContract; // Update original event Object.assign(handoffStart, completionEvent); } await this.store('handoff_completion', completionEvent, { hypothesis: this.hypothesis }); // Update quality metrics this.updateQualityMetrics(completionEvent); // Update handoff chain this.updateHandoffChainCompletion(completionEvent); return completionEvent.handoffId; } /** * Record test execution during handoff */ async recordTestExecution(data) { const testEvent = { testId: data.testId || this.generateId(), handoffId: data.handoffId, testType: data.testType, // 'unit', 'integration', 'contract', 'acceptance' testSuite: data.testSuite, startTime: data.startTime || Date.now(), endTime: data.endTime || Date.now(), passed: data.passed || 0, failed: data.failed || 0, skipped: data.skipped || 0, coverage: data.coverage || 0, assertions: data.assertions || 0, errors: data.errors || [], warnings: data.warnings || [] }; testEvent.duration = testEvent.endTime - testEvent.startTime; testEvent.total = testEvent.passed + testEvent.failed + testEvent.skipped; testEvent.successRate = testEvent.total > 0 ? testEvent.passed / testEvent.total : 0; this.testResults.push(testEvent); await this.store('test_execution', testEvent, { hypothesis: this.hypothesis }); return testEvent.testId; } /** * Record contract validation */ async recordContractValidation(data) { const validationEvent = { validationId: data.validationId || this.generateId(), handoffId: data.handoffId, contractId: data.contractId, contractType: data.contractType, // 'interface', 'behavior', 'data', 'performance' validationType: data.validationType, // 'pre_condition', 'post_condition', 'invariant' startTime: data.startTime || Date.now(), endTime: data.endTime || Date.now(), valid: data.valid !== false, violations: data.violations || [], checks: data.checks || [], severity: data.severity || 'medium', autoFixed: data.autoFixed || false }; validationEvent.duration = validationEvent.endTime - validationEvent.startTime; validationEvent.checkCount = validationEvent.checks.length; validationEvent.violationCount = validationEvent.violations.length; this.contractValidations.push(validationEvent); await this.store('contract_validation', validationEvent, { hypothesis: this.hypothesis }); // Update contract definitions tracking this.updateContractDefinitions(validationEvent); return validationEvent.validationId; } /** * Record quality gate results */ async recordQualityGate(data) { const qualityEvent = { gateId: data.gateId || this.generateId(), handoffId: data.handoffId, gateType: data.gateType, // 'pre_handoff', 'post_handoff', 'continuous' gateName: data.gateName, timestamp: Date.now(), passed: data.passed !== false, score: data.score || 0, criteria: data.criteria || [], results: data.results || {}, blockers: data.blockers || [], warnings: data.warnings || [] }; await this.store('quality_gate', qualityEvent, { hypothesis: this.hypothesis }); // Update quality gates tracking this.qualityGates.set(qualityEvent.gateId, qualityEvent); return qualityEvent.gateId; } /** * Record error or defect detected during handoff */ async recordHandoffError(data) { const errorEvent = { errorId: data.errorId || this.generateId(), handoffId: data.handoffId, errorType: data.errorType, // 'contract_violation', 'test_failure', 'validation_error', 'timeout' severity: data.severity || 'medium', // 'low', 'medium', 'high', 'critical' timestamp: Date.now(), description: data.description, stackTrace: data.stackTrace, context: data.context || {}, resolution: data.resolution, resolutionTime: data.resolutionTime || 0, preventedByContract: data.preventedByContract || false, autoResolved: data.autoResolved || false }; await this.store('handoff_error', errorEvent, { hypothesis: this.hypothesis, alert: errorEvent.severity === 'high' || errorEvent.severity === 'critical' }); // Emit alert for critical errors if (errorEvent.severity === 'critical') { this.emit('critical_error', errorEvent); } return errorEvent.errorId; } /** * Update handoff chain tracking */ updateHandoffChain(handoffEvent) { const chainKey = `${handoffEvent.fromAgent}->${handoffEvent.toAgent}`; if (!this.handoffChains.has(chainKey)) { this.handoffChains.set(chainKey, { fromAgent: handoffEvent.fromAgent, toAgent: handoffEvent.toAgent, handoffs: [], successCount: 0, totalCount: 0, averageDuration: 0, contractUsageRate: 0 }); } const chain = this.handoffChains.get(chainKey); chain.handoffs.push(handoffEvent); chain.totalCount++; } /** * Update handoff chain completion */ updateHandoffChainCompletion(completionEvent) { const chainKey = `${completionEvent.fromAgent}->${completionEvent.toAgent}`; const chain = this.handoffChains.get(chainKey); if (chain) { if (completionEvent.success) { chain.successCount++; } // Recalculate metrics const completedHandoffs = chain.handoffs.filter(h => h.endTime); if (completedHandoffs.length > 0) { const totalDuration = completedHandoffs.reduce((sum, h) => sum + (h.duration || 0), 0); chain.averageDuration = totalDuration / completedHandoffs.length; const contractHandoffs = completedHandoffs.filter(h => h.hasContract); chain.contractUsageRate = contractHandoffs.length / completedHandoffs.length; } } } /** * Update contract definitions tracking */ updateContractDefinitions(validationEvent) { if (!validationEvent.contractId) return; if (!this.contractDefinitions.has(validationEvent.contractId)) { this.contractDefinitions.set(validationEvent.contractId, { contractId: validationEvent.contractId, contractType: validationEvent.contractType, validations: [], successRate: 0, violationPatterns: new Map() }); } const contract = this.contractDefinitions.get(validationEvent.contractId); contract.validations.push(validationEvent); // Update success rate const validValidations = contract.validations.filter(v => v.valid); contract.successRate = validValidations.length / contract.validations.length; // Track violation patterns validationEvent.violations.forEach(violation => { const pattern = violation.type || 'unknown'; const currentCount = contract.violationPatterns.get(pattern) || 0; contract.violationPatterns.set(pattern, currentCount + 1); }); } /** * Update quality metrics */ updateQualityMetrics(completionEvent) { const qualityMetric = { timestamp: Date.now(), handoffId: completionEvent.handoffId, success: completionEvent.success, duration: completionEvent.duration, qualityScore: completionEvent.qualityScore, testCoverage: completionEvent.testResults?.coverage || 0, errorCount: completionEvent.errors ? completionEvent.errors.length : 0, retryCount: completionEvent.retryCount || 0, hasContract: completionEvent.hasContract }; this.qualityMetrics.push(qualityMetric); // Keep only recent metrics for performance if (this.qualityMetrics.length > 1000) { this.qualityMetrics = this.qualityMetrics.slice(-1000); } } /** * Perform TDD-specific aggregation */ performAggregation(metrics) { const baseAggregation = super.performAggregation(metrics); const handoffMetrics = metrics.filter(m => m.eventType === 'handoff_start'); const completionMetrics = metrics.filter(m => m.eventType === 'handoff_completion'); const testMetrics = metrics.filter(m => m.eventType === 'test_execution'); const validationMetrics = metrics.filter(m => m.eventType === 'contract_validation'); const errorMetrics = metrics.filter(m => m.eventType === 'handoff_error'); return { ...baseAggregation, handoffs: { totalHandoffs: handoffMetrics.length, completedHandoffs: completionMetrics.length, successfulHandoffs: completionMetrics.filter(m => m.data.success).length, contractBasedHandoffs: handoffMetrics.filter(m => m.data.hasContract).length, averageHandoffTime: this.calculateAverageHandoffTime(completionMetrics), handoffSuccessRate: this.calculateHandoffSuccessRate(completionMetrics), contractUsageRate: this.calculateContractUsageRate(handoffMetrics) }, testing: { totalTests: testMetrics.length, testSuites: this.countUnique(testMetrics, 'testSuite'), totalAssertions: testMetrics.reduce((sum, m) => sum + (m.data.assertions || 0), 0), averageTestCoverage: this.calculateAverageTestCoverage(testMetrics), testSuccessRate: this.calculateTestSuccessRate(testMetrics), averageTestDuration: this.calculateAverageTestDuration(testMetrics) }, contracts: { totalValidations: validationMetrics.length, contractTypes: this.countEventTypes(validationMetrics, 'contractType'), validationSuccessRate: this.calculateValidationSuccessRate(validationMetrics), averageValidationTime: this.calculateAverageValidationTime(validationMetrics), violationPatterns: this.analyzeViolationPatterns(validationMetrics) }, quality: { totalErrors: errorMetrics.length, errorsByType: this.countEventTypes(errorMetrics, 'errorType'), errorsBySeverity: this.countEventTypes(errorMetrics, 'severity'), averageQualityScore: this.calculateAverageQualityScore(), errorPreventionRate: this.calculateErrorPreventionRate(errorMetrics), autoResolutionRate: this.calculateAutoResolutionRate(errorMetrics) }, chains: { handoffChains: this.analyzeHandoffChains(), mostReliableChains: this.getMostReliableChains(), problematicChains: this.getProblematicChains() } }; } /** * Calculate average handoff time */ calculateAverageHandoffTime(completionMetrics) { const metricsWithDuration = completionMetrics.filter(m => m.data.duration > 0); if (metricsWithDuration.length === 0) return 0; const totalDuration = metricsWithDuration.reduce((sum, m) => sum + m.data.duration, 0); return totalDuration / metricsWithDuration.length; } /** * Calculate handoff success rate */ calculateHandoffSuccessRate(completionMetrics) { if (completionMetrics.length === 0) return 0; const successfulHandoffs = completionMetrics.filter(m => m.data.success); return successfulHandoffs.length / completionMetrics.length; } /** * Calculate contract usage rate */ calculateContractUsageRate(handoffMetrics) { if (handoffMetrics.length === 0) return 0; const contractHandoffs = handoffMetrics.filter(m => m.data.hasContract); return contractHandoffs.length / handoffMetrics.length; } /** * Calculate average test coverage */ calculateAverageTestCoverage(testMetrics) { const metricsWithCoverage = testMetrics.filter(m => m.data.coverage > 0); if (metricsWithCoverage.length === 0) return 0; const totalCoverage = metricsWithCoverage.reduce((sum, m) => sum + m.data.coverage, 0); return totalCoverage / metricsWithCoverage.length; } /** * Calculate test success rate */ calculateTestSuccessRate(testMetrics) { if (testMetrics.length === 0) return 0; const totalTests = testMetrics.reduce((sum, m) => sum + (m.data.total || 0), 0); const passedTests = testMetrics.reduce((sum, m) => sum + (m.data.passed || 0), 0); return totalTests > 0 ? passedTests / totalTests : 0; } /** * Calculate average test duration */ calculateAverageTestDuration(testMetrics) { if (testMetrics.length === 0) return 0; const totalDuration = testMetrics.reduce((sum, m) => sum + (m.data.duration || 0), 0); return totalDuration / testMetrics.length; } /** * Calculate validation success rate */ calculateValidationSuccessRate(validationMetrics) { if (validationMetrics.length === 0) return 0; const validValidations = validationMetrics.filter(m => m.data.valid); return validValidations.length / validationMetrics.length; } /** * Calculate average validation time */ calculateAverageValidationTime(validationMetrics) { if (validationMetrics.length === 0) return 0; const totalDuration = validationMetrics.reduce((sum, m) => sum + (m.data.duration || 0), 0); return totalDuration / validationMetrics.length; } /** * Count unique values for a property */ countUnique(metrics, property) { const unique = new Set(metrics.map(m => m.data[property]).filter(Boolean)); return unique.size; } /** * Count event types for a specific property */ countEventTypes(metrics, property) { const counts = {}; metrics.forEach(m => { const value = m.data[property]; if (value) { counts[value] = (counts[value] || 0) + 1; } }); return counts; } /** * Analyze violation patterns */ analyzeViolationPatterns(validationMetrics) { const patterns = new Map(); validationMetrics.forEach(m => { if (m.data.violations) { m.data.violations.forEach(violation => { const pattern = violation.type || 'unknown'; patterns.set(pattern, (patterns.get(pattern) || 0) + 1); }); } }); return Object.fromEntries( Array.from(patterns.entries()).sort((a, b) => b[1] - a[1]) ); } /** * Calculate average quality score */ calculateAverageQualityScore() { const metricsWithScore = this.qualityMetrics.filter(m => m.qualityScore > 0); if (metricsWithScore.length === 0) return 0; const totalScore = metricsWithScore.reduce((sum, m) => sum + m.qualityScore, 0); return totalScore / metricsWithScore.length; } /** * Calculate error prevention rate */ calculateErrorPreventionRate(errorMetrics) { if (errorMetrics.length === 0) return 1; // No errors means 100% prevention const preventedErrors = errorMetrics.filter(m => m.data.preventedByContract); return preventedErrors.length / errorMetrics.length; } /** * Calculate auto-resolution rate */ calculateAutoResolutionRate(errorMetrics) { if (errorMetrics.length === 0) return 0; const autoResolvedErrors = errorMetrics.filter(m => m.data.autoResolved); return autoResolvedErrors.length / errorMetrics.length; } /** * Analyze handoff chains */ analyzeHandoffChains() { const chains = Array.from(this.handoffChains.values()).map(chain => ({ from: chain.fromAgent, to: chain.toAgent, totalHandoffs: chain.totalCount, successRate: chain.totalCount > 0 ? chain.successCount / chain.totalCount : 0, averageDuration: chain.averageDuration, contractUsage: chain.contractUsageRate })); return chains.sort((a, b) => b.totalHandoffs - a.totalHandoffs); } /** * Get most reliable handoff chains */ getMostReliableChains() { return Array.from(this.handoffChains.values()) .filter(chain => chain.totalCount >= 5) // Minimum sample size .map(chain => ({ from: chain.fromAgent, to: chain.toAgent, successRate: chain.successCount / chain.totalCount, totalHandoffs: chain.totalCount })) .sort((a, b) => b.successRate - a.successRate) .slice(0, 5); } /** * Get problematic handoff chains */ getProblematicChains() { return Array.from(this.handoffChains.values()) .filter(chain => chain.totalCount >= 3) // Minimum sample size .map(chain => ({ from: chain.fromAgent, to: chain.toAgent, successRate: chain.successCount / chain.totalCount, totalHandoffs: chain.totalCount, averageDuration: chain.averageDuration })) .filter(chain => chain.successRate < 0.7) // Less than 70% success .sort((a, b) => a.successRate - b.successRate) .slice(0, 5); } /** * Perform TDD-specific analysis */ performAnalysis(metrics) { const baseAnalysis = super.performAnalysis(metrics); const handoffMetrics = metrics.filter(m => m.eventType === 'handoff_start'); const completionMetrics = metrics.filter(m => m.eventType === 'handoff_completion'); const testMetrics = metrics.filter(m => m.eventType === 'test_execution'); const validationMetrics = metrics.filter(m => m.eventType === 'contract_validation'); const errorMetrics = metrics.filter(m => m.eventType === 'handoff_error'); return { ...baseAnalysis, hypothesisValidation: { handoffSuccessRate: this.calculateHandoffSuccessRate(completionMetrics), testCoverage: this.calculateAverageTestCoverage(testMetrics), contractUsageRate: this.calculateContractUsageRate(handoffMetrics), errorReduction: this.calculateErrorReduction(errorMetrics), qualityImprovement: this.calculateQualityImprovement() }, trends: { successRateTrend: this.calculateSuccessRateTrend(completionMetrics), testCoverageTrend: this.calculateTestCoverageTrend(testMetrics), errorRateTrend: this.calculateErrorRateTrend(errorMetrics), qualityTrend: this.calculateQualityTrend() }, predictions: { projectedSuccessRate: this.projectSuccessRate(completionMetrics), timeToTargetSuccess: this.estimateTimeToTargetSuccess(completionMetrics), qualityTrajectory: this.projectQualityTrajectory(), contractAdoptionProjection: this.projectContractAdoption(handoffMetrics) } }; } /** * Calculate error reduction compared to baseline */ calculateErrorReduction(errorMetrics) { const baseline = this.baseline?.measurements?.handoffs?.retryRate || 1.0; const currentErrorRate = errorMetrics.length / Math.max(this.handoffEvents.length, 1); return Math.max(0, (baseline - currentErrorRate) / baseline); } /** * Calculate quality improvement */ calculateQualityImprovement() { const baseline = 0.5; // Assume 50% baseline quality score const current = this.calculateAverageQualityScore(); if (current === 0) return 0; return (current - baseline) / baseline; } /** * Calculate success rate trend */ calculateSuccessRateTrend(completionMetrics) { if (completionMetrics.length < 10) return 'insufficient_data'; const recentMetrics = completionMetrics.slice(-Math.floor(completionMetrics.length / 2)); const olderMetrics = completionMetrics.slice(0, Math.floor(completionMetrics.length / 2)); const recentSuccessRate = this.calculateHandoffSuccessRate(recentMetrics); const olderSuccessRate = this.calculateHandoffSuccessRate(olderMetrics); if (recentSuccessRate > olderSuccessRate * 1.05) return 'improving'; if (recentSuccessRate < olderSuccessRate * 0.95) return 'degrading'; return 'stable'; } /** * Calculate test coverage trend */ calculateTestCoverageTrend(testMetrics) { return this.calculateTrend(testMetrics, 'coverage'); } /** * Calculate error rate trend */ calculateErrorRateTrend(errorMetrics) { if (errorMetrics.length < 5) return 'insufficient_data'; // Analyze error frequency over time windows const timeWindow = 60 * 60 * 1000; // 1 hour const now = Date.now(); const recentErrors = errorMetrics.filter(m => now - m.timestamp < timeWindow ).length; const previousErrors = errorMetrics.filter(m => now - m.timestamp >= timeWindow && now - m.timestamp < timeWindow * 2 ).length; if (recentErrors < previousErrors * 0.8) return 'improving'; if (recentErrors > previousErrors * 1.2) return 'degrading'; return 'stable'; } /** * Calculate quality trend */ calculateQualityTrend() { if (this.qualityMetrics.length < 10) return 'insufficient_data'; const recentMetrics = this.qualityMetrics.slice(-Math.floor(this.qualityMetrics.length / 2)); const olderMetrics = this.qualityMetrics.slice(0, Math.floor(this.qualityMetrics.length / 2)); const recentAvg = recentMetrics.reduce((sum, m) => sum + m.qualityScore, 0) / recentMetrics.length; const olderAvg = olderMetrics.reduce((sum, m) => sum + m.qualityScore, 0) / olderMetrics.length; if (recentAvg > olderAvg * 1.05) return 'improving'; if (recentAvg < olderAvg * 0.95) return 'degrading'; return 'stable'; } /** * Calculate trend for a specific metric (inherited from parent but specialized) */ calculateTrend(metrics, property) { if (metrics.length < 10) return 'insufficient_data'; const values = metrics.map(m => m.data[property]).filter(v => v != null && v > 0); if (values.length < 10) return 'insufficient_data'; const firstThird = values.slice(0, Math.floor(values.length / 3)); const lastThird = values.slice(-Math.floor(values.length / 3)); const firstAvg = firstThird.reduce((a, b) => a + b, 0) / firstThird.length; const lastAvg = lastThird.reduce((a, b) => a + b, 0) / lastThird.length; if (lastAvg > firstAvg * 1.05) return 'improving'; if (lastAvg < firstAvg * 0.95) return 'degrading'; return 'stable'; } /** * Project success rate based on trends */ projectSuccessRate(completionMetrics) { const currentSuccessRate = this.calculateHandoffSuccessRate(completionMetrics); const trend = this.calculateSuccessRateTrend(completionMetrics); if (trend === 'improving') { return Math.min(currentSuccessRate * 1.1, 1.0); } else if (trend === 'degrading') { return Math.max(currentSuccessRate * 0.9, 0.0); } return currentSuccessRate; } /** * Estimate time to reach target success rate */ estimateTimeToTargetSuccess(completionMetrics) { const currentSuccessRate = this.calculateHandoffSuccessRate(completionMetrics); const targetSuccessRate = this.tddConfig.targetSuccessRate; if (currentSuccessRate >= targetSuccessRate) return 0; const trend = this.calculateSuccessRateTrend(completionMetrics); const improvementRate = trend === 'improving' ? 0.05 : 0.01; // 5% or 1% per hour const remainingImprovement = targetSuccessRate - currentSuccessRate; return Math.ceil(remainingImprovement / improvementRate); // Hours } /** * Project quality trajectory */ projectQualityTrajectory() { const currentQuality = this.calculateAverageQualityScore(); const trend = this.calculateQualityTrend(); const projections = []; let quality = currentQuality; for (let hours = 1; hours <= 24; hours++) { if (trend === 'improving') { quality = Math.min(quality * 1.02, 1.0); // 2% improvement per hour } else if (trend === 'degrading') { quality = Math.max(quality * 0.98, 0.0); // 2% degradation per hour } projections.push({ hour: hours, quality }); } return projections; } /** * Project contract adoption */ projectContractAdoption(handoffMetrics) { const currentUsageRate = this.calculateContractUsageRate(handoffMetrics); // Assume gradual adoption if beneficial const adoptionRate = 0.05; // 5% increase per week const projections = []; let usage = currentUsageRate; for (let week = 1; week <= 12; week++) { usage = Math.min(usage + adoptionRate, 1.0); projections.push({ week, usage }); } return projections; } /** * Validate H3: Test-Driven Development Handoffs hypothesis */ validateHypotheses(metrics) { const handoffMetrics = metrics.filter(m => m.eventType === 'handoff_start'); const completionMetrics = metrics.filter(m => m.eventType === 'handoff_completion'); const testMetrics = metrics.filter(m => m.eventType === 'test_execution'); const analysis = this.performAnalysis(metrics); const h3Validation = { hypothesis: 'Test-Driven Development handoffs improve quality and reduce errors', validated: false, confidence: this.calculateConfidence(completionMetrics.length), evidence: [], metrics: { handoffSuccessRate: analysis.hypothesisValidation?.handoffSuccessRate || 0, testCoverage: analysis.hypothesisValidation?.testCoverage || 0, contractUsageRate: analysis.hypothesisValidation?.contractUsageRate || 0, errorReduction: analysis.hypothesisValidation?.errorReduction || 0, qualityImprovement: analysis.hypothesisValidation?.qualityImprovement || 0 }, criteria: { targetSuccessRate: this.tddConfig.targetSuccessRate, targetTestCoverage: this.tddConfig.targetTestCoverage, targetErrorReduction: this.tddConfig.targetErrorReduction, confidenceThreshold: this.config.hypotheses.h3_tddHandoffs.confidenceThreshold } }; // Check validation criteria const meetsSuccessRate = h3Validation.metrics.handoffSuccessRate >= h3Validation.criteria.targetSuccessRate; const meetsTestCoverage = h3Validation.metrics.testCoverage >= h3Validation.criteria.targetTestCoverage; const meetsErrorReduction = h3Validation.metrics.errorReduction >= h3Validation.criteria.targetErrorReduction; const meetsConfidence = h3Validation.confidence >= h3Validation.criteria.confidenceThreshold; h3Validation.validated = meetsSuccessRate && meetsTestCoverage && meetsConfidence; // Collect evidence if (meetsSuccessRate) { h3Validation.evidence.push(`Handoff success rate achieved ${(h3Validation.metrics.handoffSuccessRate * 100).toFixed(1)}% (target: ${(h3Validation.criteria.targetSuccessRate * 100).toFixed(1)}%)`); } if (meetsTestCoverage) { h3Validation.evidence.push(`Test coverage achieved ${(h3Validation.metrics.testCoverage * 100).toFixed(1)}% (target: ${(h3Validation.criteria.targetTestCoverage * 100).toFixed(1)}%)`); } if (meetsErrorReduction) { h3Validation.evidence.push(`Error reduction achieved ${(h3Validation.metrics.errorReduction * 100).toFixed(1)}% (target: ${(h3Validation.criteria.targetErrorReduction * 100).toFixed(1)}%)`); } if (h3Validation.metrics.qualityImprovement > 0) { h3Validation.evidence.push(`Quality score improved by ${(h3Validation.metrics.qualityImprovement * 100).toFixed(1)}%`); } if (h3Validation.metrics.contractUsageRate > 0.8) { h3Validation.evidence.push(`High contract adoption rate: ${(h3Validation.metrics.contractUsageRate * 100).toFixed(1)}%`); } return { h1_jitLoading: { validated: false, confidence: 0, evidence: [] }, h2_hubSpoke: { validated: false, confidence: 0, evidence: [] }, h3_tddHandoffs: h3Validation }; } } module.exports = TDDHandoffMetrics;