/home/techb158/trello.abdallabala.com/src
NameSizeModeActions
riskEngine.js57560666editdlrm
server.js50850666editdlrm
store.js11730666editdlrm
Edit: /home/techb158/trello.abdallabala.com/src/riskEngine.js (5756B)
const DIMENSION_WEIGHTS = { organizational: 0.34, technical: 0.43, human: 0.23 }; const LIFECYCLE_WEIGHTS = { needs_analysis: 1.0, data_preparation: 1.25, design: 1.1, model_development: 1.35, testing_evaluation: 1.3, deployment_monitoring: 1.4 }; const TYPOLOGY_WEIGHTS = { incremental: 0.85, disruptive: 1.25, applied_research: 1.2, ai_enabler: 1.05, citizen_led: 1.15 }; const MATURITY_DISCOUNT = { ad_hoc: 1.2, defined: 1.0, measured: 0.9, controlled: 0.8 }; function clamp(value, min, max) { const numeric = Number(value); if (Number.isNaN(numeric)) return min; return Math.max(min, Math.min(max, numeric)); } function normalizeItem(item) { const probability = clamp(item.probability ?? 3, 1, 5); const impact = clamp(item.impact ?? 3, 1, 5); const detectionDifficulty = clamp(item.detectionDifficulty ?? 3, 1, 5); const mitigationCompleteness = clamp(item.mitigationCompleteness ?? 0, 0, 100); const residualFactor = 1 - mitigationCompleteness / 100; return { id: item.id, title: item.title || 'Untitled risk', category: item.category || 'technical', dimension: item.dimension || 'technical', lifecyclePhase: item.lifecyclePhase || 'model_development', probability, impact, detectionDifficulty, mitigationCompleteness, owner: item.owner || null, dueDate: item.dueDate || null, mitigation: item.mitigation || '', approvalState: item.approvalState || 'draft', rawScore: probability * impact * detectionDifficulty, residualScore: probability * impact * detectionDifficulty * residualFactor }; } function statusFromScore(score) { if (score >= 55) return 'critical'; if (score >= 35) return 'high'; if (score >= 18) return 'medium'; return 'low'; } function approvalGateStatus({ status, approvalState, mitigationCompleteness, metrics = {} }) { const blocking = []; if (status === 'critical') blocking.push('Critical residual risk requires explicit approval.'); if (mitigationCompleteness < 60) blocking.push('Mitigation completeness is below 60%.'); if (!['approved', 'accepted'].includes(approvalState)) blocking.push('Risk is not approved or accepted.'); if (metrics.modelPerformanceScore !== undefined && Number(metrics.modelPerformanceScore) < 70) { blocking.push('Model performance score is below 70%.'); } if (metrics.dataReadinessScore !== undefined && Number(metrics.dataReadinessScore) < 70) { blocking.push('Data readiness score is below 70%.'); } if (metrics.ethicalReviewCompleted === false) blocking.push('Ethical review is not completed.'); if (metrics.legalReviewCompleted === false) blocking.push('Legal review is not completed.'); return { deploymentReady: blocking.length === 0, blockingReasons: blocking }; } export function scoreRiskAssessment(input = {}) { const projectTypology = input.projectTypology || 'ai_enabler'; const lifecyclePhase = input.lifecyclePhase || 'model_development'; const maturity = input.measurementMaturity || 'defined'; const metrics = input.metrics || {}; const items = Array.isArray(input.risks) ? input.risks.map(normalizeItem) : []; const dimensionTotals = { organizational: 0, technical: 0, human: 0 }; for (const item of items) { const dimension = dimensionTotals[item.dimension] !== undefined ? item.dimension : 'technical'; dimensionTotals[dimension] += item.residualScore; } const weightedDimensionScore = Object.entries(dimensionTotals).reduce((sum, [dimension, total]) => { return sum + total * (DIMENSION_WEIGHTS[dimension] || 0.33); }, 0); const lifecycleMultiplier = LIFECYCLE_WEIGHTS[lifecyclePhase] || 1; const typologyMultiplier = TYPOLOGY_WEIGHTS[projectTypology] || 1; const maturityMultiplier = MATURITY_DISCOUNT[maturity] || 1; const normalizedScore = Math.round( clamp(weightedDimensionScore * lifecycleMultiplier * typologyMultiplier * maturityMultiplier, 0, 100) ); const status = statusFromScore(normalizedScore); const averageMitigation = items.length ? Math.round(items.reduce((sum, item) => sum + item.mitigationCompleteness, 0) / items.length) : 0; const highestRisk = [...items].sort((a, b) => b.residualScore - a.residualScore)[0] || null; const approvalState = input.approvalState || 'draft'; const gate = approvalGateStatus({ status, approvalState, mitigationCompleteness: averageMitigation, metrics }); return { projectTypology, lifecyclePhase, measurementMaturity: maturity, score: normalizedScore, status, averageMitigationCompleteness: averageMitigation, dimensionTotals, highestRisk, gate, risks: items, interpretation: buildInterpretation(normalizedScore, status, gate) }; } function buildInterpretation(score, status, gate) { const base = `Residual AI project risk is ${status} with a normalized score of ${score}/100.`; if (gate.deploymentReady) { return `${base} Deployment gate can proceed if accountable stakeholders approve the record.`; } return `${base} Deployment gate is blocked by ${gate.blockingReasons.length} criterion or criteria.`; } export function getReferenceTaxonomy() { return { lifecyclePhases: Object.keys(LIFECYCLE_WEIGHTS), projectTypologies: Object.keys(TYPOLOGY_WEIGHTS), maturityLevels: Object.keys(MATURITY_DISCOUNT), dimensions: Object.keys(DIMENSION_WEIGHTS), categories: ['strategic_organizational', 'technical', 'legal_ethical'], gateCriteria: [ 'risk_status', 'mitigation_completeness', 'approval_state', 'model_performance_metrics', 'data_readiness', 'ethical_review', 'legal_review', 'deployment_readiness' ] }; }