id(); $configured_name = $configured->name(); $fallback_used = false; $error_message = null; $used = $configured; try { $review = $configured->review_trace( $trace, $deterministic_audit ); } catch ( \Throwable $e ) { // Fallback to simulated on any error from the configured provider $fallback = new SA_Orch_LLM_Provider_Simulated(); $review = $fallback->review_trace( $trace, $deterministic_audit ); $error_message = $e->getMessage(); $fallback_used = true; $used = $fallback; } // Defensive: enforce required keys $review = wp_parse_args( $review, [ 'summary' => '', 'agreement_with_audit' => 'partial', 'additional_risks' => [], 'suggested_next_action' => '', 'confidence' => 'low', ] ); // Conservative confidence floor (v0.5.2): when the deterministic audit // cannot evaluate closure (closure_confidence='n/a' — i.e. no acceptance // events recorded), the strategy layer MUST collapse to 'low'. Prevents // LLM-shaped over-confidence on Demands with no acceptance evidence. // Cross-cutting: applied here so any provider (including future ones) // gets it for free, regardless of what the model returned. if ( ( $deterministic_audit['closure_confidence'] ?? '' ) === 'n/a' && in_array( $review['confidence'], [ 'medium', 'high' ], true ) ) { $review['confidence'] = 'low'; } // Provider used to actually produce this output $review['provider_id'] = $used->id(); $review['provider_name'] = $used->name(); // Configured provider (what the operator selected) $review['configured_provider_id'] = $configured_id; $review['configured_provider_name'] = $configured_name; // Fallback transparency $review['fallback_used'] = $fallback_used; if ( $error_message !== null ) { $review['provider_error'] = $error_message; } return $review; } }