diff --git a/public/js/admin/audit-analytics.js b/public/js/admin/audit-analytics.js index b725f0e6..b3ebd95b 100644 --- a/public/js/admin/audit-analytics.js +++ b/public/js/admin/audit-analytics.js @@ -121,7 +121,8 @@ function updateSummaryCards() { const totalDecisions = auditData.length; const allowedCount = auditData.filter(d => d.allowed).length; const blockedCount = auditData.filter(d => !d.allowed).length; - const violationsCount = auditData.filter(d => d.violations && d.violations.length > 0).length; + // Count total violations across all decisions (not just decisions with violations) + const violationsCount = auditData.reduce((sum, d) => sum + (d.violations ? d.violations.length : 0), 0); const servicesSet = new Set(auditData.map(d => d.service).filter(s => s && s !== 'unknown')); document.getElementById('total-decisions').textContent = totalDecisions; @@ -304,8 +305,19 @@ async function renderBusinessIntelligence() { progressBar.style.width = maturityScore + '%'; // PHASE 3.4: Framework Participation Rate + // All decisions from framework services represent framework participation + const frameworkServices = [ + 'FileEditHook', + 'BoundaryEnforcer', + 'ContextPressureMonitor', + 'MetacognitiveVerifier', + 'CrossReferenceValidator', + 'InstructionPersistenceClassifier', + 'PluralisticDeliberationOrchestrator' + ]; + const frameworkBackedDecisions = auditData.filter(d => - d.metadata && d.metadata.framework_backed_decision === true + frameworkServices.includes(d.service) ); const participationRate = auditData.length > 0 ? ((frameworkBackedDecisions.length / auditData.length) * 100).toFixed(1) @@ -356,11 +368,13 @@ async function renderBusinessIntelligence() { } // Team Comparison (AI vs Human) + // Use same framework services list defined above const aiDecisions = auditData.filter(d => - d.service === 'FileEditHook' || d.service === 'BoundaryEnforcer' || - d.service === 'ContextPressureMonitor' || d.service === 'MetacognitiveVerifier' + frameworkServices.includes(d.service) + ); + const humanDecisions = auditData.filter(d => + !frameworkServices.includes(d.service) && d.service && d.service !== 'unknown' ); - const humanDecisions = auditData.filter(d => !aiDecisions.includes(d)); const comparisonEl = document.getElementById('team-comparison'); comparisonEl.innerHTML = ''; diff --git a/src/controllers/audit.controller.js b/src/controllers/audit.controller.js index 1ba1c0f4..99269c59 100644 --- a/src/controllers/audit.controller.js +++ b/src/controllers/audit.controller.js @@ -105,7 +105,7 @@ async function getAuditAnalytics(req, res) { total: decisions.length, allowed: allowedDecisions.length, blocked: blockedDecisions.length, - violations: decisions.filter(d => d.violations && d.violations.length > 0).length, + violations: decisions.reduce((sum, d) => sum + (d.violations ? d.violations.length : 0), 0), // Block metrics blockRate: decisions.length > 0 ? ((blockedDecisions.length / decisions.length) * 100).toFixed(1) : 0, @@ -345,17 +345,23 @@ async function getAuditAnalytics(req, res) { // === AI vs HUMAN PERFORMANCE === - // Detect AI vs Human based on service patterns - // AI = FileEditHook, Framework services - // Human = Manual overrides, direct database operations + // All framework services are AI-assisted decisions + // Framework services: ALL decisions in audit logs are framework-backed + const frameworkServices = [ + 'FileEditHook', + 'BoundaryEnforcer', + 'ContextPressureMonitor', + 'MetacognitiveVerifier', + 'CrossReferenceValidator', + 'InstructionPersistenceClassifier', + 'PluralisticDeliberationOrchestrator' + ]; + const aiDecisions = decisions.filter(d => - d.service === 'FileEditHook' || - d.service === 'BoundaryEnforcer' || - d.service === 'ContextPressureMonitor' || - d.service === 'MetacognitiveVerifier' + frameworkServices.includes(d.service) ); const humanDecisions = decisions.filter(d => - !aiDecisions.includes(d) + !frameworkServices.includes(d.service) && d.service && d.service !== 'unknown' ); const aiBlocked = aiDecisions.filter(d => !d.allowed).length; @@ -376,6 +382,11 @@ async function getAuditAnalytics(req, res) { } }; + // Calculate overall block rate (needed for maturity score) + const totalDecisions = decisions.length; + const totalBlocks = blockedDecisions.length; + const avgBlockRate = totalDecisions > 0 ? (totalBlocks / totalDecisions) : 0; + // Framework Maturity Score (0-100) // Based on: block rate trend, severity distribution, learning curve const recentDays = 7; @@ -411,9 +422,6 @@ async function getAuditAnalytics(req, res) { }; // ROI Projections - const totalDecisions = decisions.length; - const totalBlocks = blockedDecisions.length; - const avgBlockRate = totalDecisions > 0 ? (totalBlocks / totalDecisions) : 0; analytics.roiProjections = { // Current period metrics