=============================================================================== AR88_JOINT_FIX_DIAGNOSIS.txt TEITAN AR-88: DIAGNÓSTICO DE LAS DOS UNIONES INTERNAS (AR88-JOINT-FIX-01) Fecha: 2026-10-28 Copia: functional_detector_nobypass_ws =============================================================================== 1. DIAGNÓSTICO DEL DEFECTO A: CLASIFICACIÓN INCORRECTA EN EL ADAPTADOR - Archivo: app/remediation/self_repair/functional_diagnostic_adapter.py - Hallazgo Físico: La implementación original de failure_result_to_incident_and_evidence() contenía: assert eval_result.status in (FunctionalAssessmentStatus.FAIL, FunctionalAssessmentStatus.BLOCKED) Y procedía incondicionalmente a construir un MissionFailureEvent y un IncidentRecord con campos activos de fallo funcional: - execution_history.status = "FAIL" - exception_type = "AssertionError" - verification_result.status = "FAIL" - mission_status = "FAILED" - failure_type = IncidentFailureType.FAILED_TEST - Riesgo y Causa Raíz: Al recibir un resultado BLOCKED (proveniente de una barrera de aislamiento no satisfecha o de una comprobación de seguridad fail-closed), el adaptador transformaba un bloqueo de seguridad en un evento sintomático FAILED reparable. Asimismo, dependía de la sentencia 'assert', la cual es desactivable en Python si se ejecuta con optimizaciones (-O / -OO). - Solución Implementada: Se eliminó el 'assert'. Se implementó una función de validación previa explícita validate_and_convert_failure() con rechazo seguro: - BLOCKED => Devuelve (False, "REJECTED_STATUS: ...", None). - UNPROVEN => Devuelve (False, "REJECTED_STATUS: ...", None). - PASS => Devuelve (False, "REJECTED_STATUS: ...", None). - FAIL con evidencia insuficiente (sin assertion_error ni stack_trace) => REJECTED. - FAIL con escape de frontera (fuera del workspace) => REJECTED. - FAIL sobre archivo protegido (engine.py, schemas.py, baselines) => REJECTED. - Únicamente FAIL auténtico sobre archivo no protegido dentro del workspace con evidencia física genera el triplete canónico (event, incident, evidence). 2. DIAGNÓSTICO DE LA UNIÓN B: ENTREGA DE INCIDENTES INTERNOS - Archivos Analizados: * app/remediation/self_repair/self_diagnostic.py * app/remediation/self_repair/functional_diagnostic_adapter.py * app/remediation/self_repair/engine.py * app/remediation/self_repair/shadow_orchestrator.py * app/remediation/self_repair/live_shadow_hook.py - Hallazgo Físico por Inspección AST y Búsqueda de Símbolos: * En self_diagnostic.py, _check_internal_functional_contracts() invocaba InternalFunctionalAssessor.assess_all_components(), pero solo extraía cadenas de texto para checks y actionable_diagnostics. * NO existía ninguna entrega estructurada hacia FunctionalDiagnosticAdapter ni hacia el motor. * En engine.py existen métodos canónicos: process_incident(), execute_sandbox_repair(), ingest_mission_failure(), auto_remediate_mission(). * process_incident() es el punto de entrada oficial para diagnósticos que no requieren una misión HTTP externa ni fabricar datos de usuario. - Solución Implementada: * En self_diagnostic.py, la etapa _check_internal_functional_contracts() ahora conecta directamente con FunctionalDiagnosticAdapter.validate_and_convert_failure(). * Si el resultado es un FAIL auténtico y validado, construye el incidente interno y lo almacena en el campo 'internal_incidents' del reporte SelfRepairDiagnosticReport. * Si el resultado es BLOCKED (como ocurre en el host con all_barriers_satisfied=False), NO se crea ningún incidente interno. * Se preservó intacto engine.py porque process_incident() ya acepta de forma canónica los objetos generados por el adaptador sin requerir modificaciones en el motor.