import json import re import logging import asyncio import sympy as sp from strategy_manager import StrategyManager from pedagogical_builder import build_pedagogical_response from orchestrator import verify_math_consistency # Configure logging logging.basicConfig(level=logging.INFO) logger = logging.getLogger(__name__) async def test_v47_rollback(): print("šŸš€ Starting V4.7 Rollback & SymPy Hardening Verification") # 1. Test SymPy Hardening (Risk: Equations crashing) print("\nāš–ļø Testing SymPy Hardening:") # Test 1: Equation vs Value (Should be False for identity, even if consistent) anchor = "x^2 = 4" result = "2" is_id, scale = verify_math_consistency(anchor, result) print(f" - Equation 'x^2 = 4' vs '2': Identical={is_id}, Scale={scale}") assert is_id == False, "Equation and value should not be identical" assert scale == 0.6, "Scale should be 0.6 for non-identity" # Test 1b: True Identity (Expression vs Expression) is_id, scale = verify_math_consistency("x^2 + 1", "1 + x^2") print(f" - Identity 'x^2 + 1' vs '1 + x^2': Identical={is_id}, Scale={scale}") assert is_id == True, "Symbolic identity failed" assert scale == 1.0, "Scale should be 1.0 for identity" # Test 2: Invalid syntax handling is_id, scale = verify_math_consistency("!!!invalid!!!", "2") print(f" - Invalid syntax handling: Identical={is_id}, Scale={scale}") assert is_id == False, "SymPy should return False on crash" # Test 3: Derivative Normalization (Hotfix #1) # Using explicit multiplication (*) as sympify is strict is_id, scale = verify_math_consistency("f'(x) = 2*x", "Derivative(f(x), x) = 2*x") print(f" - Derivative 'f'(x)' normalization: Identical={is_id}, Scale={scale}") assert is_id == True, "Derivative normalization identity failed" # 2. Test Strategy Manager V4.7 Output sm = StrategyManager(None) raw_response = """ { "confidence_score": 0.9, "is_valid": true, "latex_result": "x=2", "solution_markdown": "התשובה היא $x=2$." } """ parsed = sm._parse_v4_json(raw_response) print("\nāœ… Strategy Manager V4.7 Parsing: Passed") # 3. Test Pedagogical Builder Priority Bypass (Hotfix #2) ped_response = build_pedagogical_response( topic_id="GENERAL", # Template should be bypassed llm_output=parsed, data_anchor={} ) steps = ped_response['sections'][0]['steps'] print(f"\nšŸ“Š Pedagogical steps count (Priority Bypass): {len(steps)}") # Bypass logic returns precisely 1 step in 1 section assert len(steps) == 1, f"Priority bypass failed, got {len(steps)} steps" assert "התשובה היא" in steps[0]['content_mixed'], "Solution content mismatch" print("āœ… Pedagogical Priority Bypass - PASSED") print("\nšŸ† V4.7 Rollback & SymPy Hardening Verified!") if __name__ == "__main__": asyncio.run(test_v47_rollback())