# domain/risk_engine.py import logging from typing import Dict, Any, List from .curriculum_classifier import CurriculumClassifier logger = logging.getLogger(__name__) class CognitiveRiskEngine: """ V6.1 Phase 4: Risk Scoring Evaluates the cognitive risk of a proposal based on AST complexity, step count, retries, and symbolic stability. """ WEIGHTS = { "ast_complexity": 0.30, "reasoning_depth": 0.20, "retry_penalty": 0.25, "symbolic_instability": 0.25 } @classmethod def calculate_risk_score(cls, math_input: str, draft_steps: List[Dict[str, Any]], retry_count: int, validation_errors: int) -> Dict[str, Any]: """ Calculates the Cognitive Risk Score (CRS) between 0.0 and 1.0. """ # 1. AST Complexity (normalized 0-1) # We reuse CurriculumClassifier's internal complexity estimation if possible, # but here we normalize it against a ceiling of 20. raw_complexity = CurriculumClassifier.estimate_complexity(math_input) ast_risk = min(raw_complexity / 20.0, 1.0) # 2. Reasoning Depth (normalized 0-1) # 10 steps is considered high depth for our MVP depth_risk = min(len(draft_steps) / 10.0, 1.0) # 3. Retry Penalty # 0 retries = 0.0, 1 retry = 1.0 (since max retry is 1 in V6.1) retry_risk = 1.0 if retry_count > 0 else 0.0 # 4. Symbolic Instability # Based on validation failures during the process instability_risk = min(validation_errors / 5.0, 1.0) # Weighted Final Score crs = (ast_risk * cls.WEIGHTS["ast_complexity"] + depth_risk * cls.WEIGHTS["reasoning_depth"] + retry_risk * cls.WEIGHTS["retry_penalty"] + instability_risk * cls.WEIGHTS["symbolic_instability"]) result = { "risk_score": round(crs, 3), "features": { "ast_risk": round(ast_risk, 3), "depth_risk": round(depth_risk, 3), "retry_risk": retry_risk, "instability_risk": round(instability_risk, 3) } } logger.info(f"🧠 [RISK_ENGINE] Calculated CRS: {result['risk_score']} (AST: {ast_risk}, Depth: {depth_risk}, Retry: {retry_risk})") return result