mockforge_intelligence/ai_contract_diff/mod.rs
1//! Pillars: [Contracts][AI]
2//!
3//! AI-powered contract diff analysis
4//!
5//! This module provides intelligent contract diff analysis that compares front-end requests
6//! against backend API contract specifications, detects mismatches, and generates AI-powered
7//! recommendations and correction proposals.
8//!
9//! # Features
10//!
11//! - **Structural Diff Analysis**: Detects mismatches between requests and contract specs
12//! - **AI-Powered Recommendations**: Uses LLM to generate contextual recommendations
13//! - **Correction Proposals**: Generates JSON Patch files for schema corrections
14//! - **Confidence Scoring**: Provides confidence scores for all suggestions
15//!
16//! # Example Usage
17//!
18//! ```rust,ignore
19//! use mockforge_core::ai_contract_diff::{
20//! ContractDiffAnalyzer, ContractDiffConfig, CapturedRequest,
21//! };
22//! use mockforge_core::openapi::OpenApiSpec;
23//!
24//! async fn example() -> mockforge_core::Result<()> {
25//! // Load contract specification
26//! let spec = OpenApiSpec::from_file("api.yaml").await?;
27//!
28//! // Configure contract diff
29//! let config = ContractDiffConfig {
30//! enabled: true,
31//! llm_provider: "openai".to_string(),
32//! llm_model: "gpt-4".to_string(),
33//! confidence_threshold: 0.5,
34//! ..Default::default()
35//! };
36//!
37//! // Create analyzer
38//! let analyzer = ContractDiffAnalyzer::new(config)?;
39//!
40//! // Capture a request
41//! let request = CapturedRequest::new("POST", "/api/users", "browser_extension")
42//! .with_body(serde_json::json!({"name": "Alice", "email": "alice@example.com"}));
43//!
44//! // Analyze request against contract
45//! let result = analyzer.analyze(request, &spec).await?;
46//!
47//! // Check results
48//! if !result.matches {
49//! println!("Found {} mismatches", result.mismatches.len());
50//! for mismatch in &result.mismatches {
51//! println!(" - {}: {}", mismatch.path, mismatch.description);
52//! }
53//!
54//! // Generate recommendations
55//! for recommendation in &result.recommendations {
56//! println!(" Recommendation: {}", recommendation.recommendation);
57//! }
58//!
59//! // Generate correction proposals
60//! for correction in &result.corrections {
61//! println!(" Correction: {}", correction.description);
62//! }
63//! }
64//! Ok(())
65//! }
66//! ```
67
68pub mod confidence_scorer;
69pub mod correction_proposer;
70pub mod diff_analyzer;
71pub mod recommendation_engine;
72pub mod semantic_analyzer;
73pub mod types;
74
75// Re-export main types
76pub use confidence_scorer::{ConfidenceScorer, ScoringContext};
77pub use correction_proposer::CorrectionProposer;
78pub use diff_analyzer::DiffAnalyzer;
79pub use recommendation_engine::{RecommendationEngine, RequestContext};
80pub use semantic_analyzer::{SemanticAnalyzer, SemanticChangeType, SemanticDriftResult};
81pub use types::ConfidenceLevel;
82pub use types::{
83 CapturedRequest, ContractDiffConfig, ContractDiffResult, CorrectionProposal, DiffMetadata,
84 Mismatch, MismatchSeverity, MismatchType, PatchOperation, Recommendation,
85};
86
87/// Main contract diff analyzer that orchestrates all components
88pub struct ContractDiffAnalyzer {
89 /// Diff analyzer for structural comparison
90 diff_analyzer: DiffAnalyzer,
91
92 /// Recommendation engine for AI-powered suggestions
93 recommendation_engine: RecommendationEngine,
94
95 /// Semantic analyzer for Layer 2 semantic drift detection
96 semantic_analyzer: SemanticAnalyzer,
97
98 /// Correction proposer for generating patches
99 #[allow(dead_code)]
100 correction_proposer: CorrectionProposer,
101
102 /// Configuration
103 config: ContractDiffConfig,
104}
105
106impl ContractDiffAnalyzer {
107 /// Create a new contract diff analyzer
108 pub fn new(config: ContractDiffConfig) -> mockforge_foundation::Result<Self> {
109 let diff_analyzer = DiffAnalyzer::new(config.clone());
110 let recommendation_engine = RecommendationEngine::new(config.clone())?;
111 let semantic_analyzer = SemanticAnalyzer::new(config.clone())?;
112 let correction_proposer = CorrectionProposer;
113
114 Ok(Self {
115 diff_analyzer,
116 recommendation_engine,
117 semantic_analyzer,
118 correction_proposer,
119 config,
120 })
121 }
122
123 /// Analyze a captured request against a contract specification
124 pub async fn analyze(
125 &self,
126 request: &CapturedRequest,
127 spec: &mockforge_openapi::OpenApiSpec,
128 ) -> mockforge_foundation::Result<ContractDiffResult> {
129 // Step 1: Perform structural diff analysis
130 let mut result = self.diff_analyzer.analyze_request(request, spec).await?;
131
132 // Step 2: Generate AI-powered recommendations if enabled
133 if self.config.use_ai_recommendations && !result.mismatches.is_empty() {
134 let mut request_context = RequestContext::new(&request.method, &request.path);
135 if let Some(body) = &request.body {
136 request_context = request_context.with_body(body.clone());
137 }
138 request_context =
139 request_context.with_contract_format(&result.metadata.contract_format);
140
141 let recommendations = self
142 .recommendation_engine
143 .generate_recommendations(&result.mismatches, &request_context)
144 .await?;
145
146 // Filter by confidence threshold
147 result.recommendations = recommendations
148 .into_iter()
149 .filter(|r| r.confidence >= self.config.confidence_threshold)
150 .collect();
151 }
152
153 // Step 3: Generate correction proposals if enabled
154 if self.config.generate_corrections && !result.mismatches.is_empty() {
155 result.corrections = CorrectionProposer::generate_proposals(
156 &result.mismatches,
157 &result.recommendations,
158 spec,
159 );
160
161 // Filter by confidence threshold
162 result.corrections.retain(|c| c.confidence >= self.config.confidence_threshold);
163 }
164
165 // Recalculate overall confidence with recommendations and corrections
166 result.confidence = ConfidenceScorer::calculate_overall_confidence(&result.mismatches);
167
168 // Record AI pillar usage (ai_generation type=contract_diff) so the dashboard reflects contract-diff activity.
169 mockforge_foundation::pillar_tracking::record_ai_usage(
170 None,
171 None,
172 "ai_generation",
173 serde_json::json!({
174 "type": "contract_diff",
175 "mismatches": result.mismatches.len(),
176 "recommendations": result.recommendations.len(),
177 "corrections": result.corrections.len(),
178 }),
179 )
180 .await;
181
182 Ok(result)
183 }
184
185 /// Compare two contract specifications and detect semantic drift
186 ///
187 /// This method performs Layer 1 (structural) and Layer 2 (semantic) analysis
188 /// to detect both structural and meaning changes between contract versions.
189 pub async fn compare_specs(
190 &self,
191 before_spec: &mockforge_openapi::OpenApiSpec,
192 after_spec: &mockforge_openapi::OpenApiSpec,
193 endpoint_path: &str,
194 method: &str,
195 ) -> mockforge_foundation::Result<Option<SemanticDriftResult>> {
196 // Layer 2: Semantic analysis
197 if self.config.semantic_analysis_enabled {
198 let semantic_result = self
199 .semantic_analyzer
200 .analyze_semantic_drift(before_spec, after_spec, endpoint_path, method)
201 .await?;
202
203 // Filter by semantic confidence threshold
204 if let Some(ref result) = semantic_result {
205 if result.semantic_confidence >= self.config.semantic_confidence_threshold {
206 return Ok(semantic_result);
207 }
208 }
209 }
210
211 Ok(None)
212 }
213
214 /// Generate a JSON Patch file from correction proposals
215 pub fn generate_patch_file(
216 &self,
217 corrections: &[CorrectionProposal],
218 spec_version: &str,
219 ) -> serde_json::Value {
220 CorrectionProposer::generate_patch_file(corrections, spec_version)
221 }
222
223 /// Get configuration
224 pub fn config(&self) -> &ContractDiffConfig {
225 &self.config
226 }
227}