Skip to main content

CracklePattern

Struct CracklePattern 

Source
pub struct CracklePattern { /* private fields */ }
Expand description

A pattern detected during the cooling phase.

Like a craze line in pottery glaze, each pattern is a record of something that wasn’t designed — it emerged from the interaction of many tasks as the system cooled.

Implementations§

Source§

impl CracklePattern

Source

pub fn new( kind: PatternKind, description: impl Into<String>, involved_tasks: Vec<String>, confidence: f64, ) -> Self

Create a new detected pattern.

Source

pub fn kind(&self) -> &PatternKind

The kind of pattern detected.

Examples found in repository?
examples/basic.rs (line 44)
29fn main() {
30    let mut kiln = Kiln::new(ThermalProfile::fast_cooling());
31
32        kiln.fire_and_record(NumberTask { value: 2.0, name: "a".into() }).unwrap();
33    kiln.fire_and_record(NumberTask { value: 2.1, name: "b".into() }).unwrap();
34    kiln.fire_and_record(NumberTask { value: 9.8, name: "c".into() }).unwrap();
35    kiln.fire_and_record(NumberTask { value: 10.0, name: "d".into() }).unwrap();
36    kiln.fire_and_record(NumberTask { value: 2.2, name: "e".into() }).unwrap();
37
38    println!("Tasks in kiln: {}", kiln.task_count());
39
40    let patterns = kiln.cool();
41    println!("\nDetected {} pattern(s):\n", patterns.len());
42
43    for p in &patterns {
44        println!("[{}] {}", p.kind(), p.description());
45        println!("  confidence: {:.2}", p.confidence());
46        println!("  tasks: {:?}\n", p.involved_tasks());
47    }
48}
More examples
Hide additional examples
examples/ci_patterns.rs (line 47)
30fn main() {
31    let mut kiln = Kiln::new(ThermalProfile::default());
32
33    // Normal builds
34    kiln.fire_and_record(CiBuild { duration_secs: 45.0, test_count: 200.0, branch: "feature/auth".into() }).unwrap();
35    kiln.fire_and_record(CiBuild { duration_secs: 42.0, test_count: 195.0, branch: "fix/typo".into() }).unwrap();
36    kiln.fire_and_record(CiBuild { duration_secs: 48.0, test_count: 210.0, branch: "feature/ui".into() }).unwrap();
37
38    // Something changed — builds got slower
39    kiln.fire_and_record(CiBuild { duration_secs: 95.0, test_count: 200.0, branch: "feature/cache".into() }).unwrap();
40    kiln.fire_and_record(CiBuild { duration_secs: 102.0, test_count: 198.0, branch: "chore/deps".into() }).unwrap();
41
42    let patterns = kiln.cool();
43    println!("CI Build Pattern Analysis");
44    println!("=========================\n");
45
46    for p in &patterns {
47        println!("[{}] {}", p.kind().to_string().to_uppercase(), p.description());
48        println!("  confidence: {:.2}", p.confidence());
49        println!("  branches: {:?}\n", p.involved_tasks());
50    }
51
52    // Check for phase transition in build duration
53    let phase_shifts: Vec<_> = patterns.iter()
54        .filter(|p| format!("{}", p.kind()) == "phase transition")
55        .collect();
56
57    if !phase_shifts.is_empty() {
58        println!("⚠️  Build duration shifted significantly — investigate recent changes!");
59    }
60}
examples/api_monitoring.rs (line 54)
32fn main() {
33    let mut kiln = Kiln::new(ThermalProfile::default());
34
35    // /api/users — fast, small responses
36    kiln.fire_and_record(ApiRequest { endpoint: "GET /api/users".into(), latency_ms: 45.0, status: 200, response_bytes: 1200.0 }).unwrap();
37    kiln.fire_and_record(ApiRequest { endpoint: "GET /api/users".into(), latency_ms: 48.0, status: 200, response_bytes: 1150.0 }).unwrap();
38    kiln.fire_and_record(ApiRequest { endpoint: "GET /api/users".into(), latency_ms: 52.0, status: 200, response_bytes: 1300.0 }).unwrap();
39
40    // /api/reports — slow, large responses (correlated with bytes)
41    kiln.fire_and_record(ApiRequest { endpoint: "GET /api/reports".into(), latency_ms: 350.0, status: 200, response_bytes: 55000.0 }).unwrap();
42    kiln.fire_and_record(ApiRequest { endpoint: "GET /api/reports".into(), latency_ms: 380.0, status: 200, response_bytes: 62000.0 }).unwrap();
43
44    // /api/health — tiny, always fast (conservation candidate)
45    kiln.fire_and_record(ApiRequest { endpoint: "GET /api/health".into(), latency_ms: 3.0, status: 200, response_bytes: 15.0 }).unwrap();
46    kiln.fire_and_record(ApiRequest { endpoint: "GET /api/health".into(), latency_ms: 4.0, status: 200, response_bytes: 15.0 }).unwrap();
47
48    let patterns = kiln.cool();
49    println!("API Monitoring — Pattern Report");
50    println!("================================\n");
51    println!("{} patterns detected:\n", patterns.len());
52
53    for p in &patterns {
54        println!("[{}] {}", p.kind(), p.description());
55        println!("  confidence: {:.2}", p.confidence());
56        if !p.involved_tasks().is_empty() {
57            println!("  endpoints: {:?}", p.involved_tasks());
58        }
59        println!();
60    }
61
62    // Highlight correlations between latency and response size
63    let correlations: Vec<_> = patterns.iter()
64        .filter(|p| format!("{}", p.kind()) == "correlation")
65        .collect();
66
67    if !correlations.is_empty() {
68        println!("📊 Latency and response size are correlated — consider pagination or caching.");
69    }
70}
examples/event_stream_processor.rs (line 133)
98fn main() {
99    let total_events = 1000;
100    let batch_size = 100;
101    let num_batches = total_events / batch_size;
102
103    println!("═══════════════════════════════════════════════════════════════");
104    println!("  CRACKLE-RUNTIME: EVENT STREAM PROCESSOR TEST");
105    println!("═══════════════════════════════════════════════════════════════\n");
106    println!("Processing {} events across {} batches of {}...\n",
107             total_events, num_batches, batch_size);
108
109    let start = Instant::now();
110
111    // Phase 1: Healthy system (batches 1-4)
112    println!("─── Phase 1: Healthy System ───");
113    let mut healthy_kiln = Kiln::new(
114        ThermalProfile::fast_cooling()
115    );
116
117    // Batch 1-4: all healthy, 10ms baseline latency
118    for batch_id in 1..=4 {
119        let events = simulate_batch(batch_id, batch_size as u32, 10.0, 0.05);
120        for event in events {
121            healthy_kiln.fire_and_record(event).unwrap();
122        }
123
124        let elapsed = start.elapsed();
125        println!("  Batch {}/{} fired ({} events, {:.0}ms)",
126                 batch_id, num_batches, batch_size, elapsed.as_millis());
127    }
128
129    // Cool healthy phase
130    let healthy_patterns = healthy_kiln.cool();
131    println!("\n  Healthy system patterns ({} detected):", healthy_patterns.len());
132    for p in &healthy_patterns {
133        println!("    [{:?}] {} (conf: {:.2})", p.kind(), p.description(), p.confidence());
134    }
135    // Also check conservation on records_in/records_out
136    let conservation = healthy_kiln.distribution_shift(10);
137    println!("    Distribution shifts:");
138    for (name, shift) in &conservation[..conservation.len().min(3)] {
139        println!("      {} → KL = {:.4}", name, shift);
140    }
141
142    println!();
143
144    // Phase 2: Degrading system (batches 5-8)
145    println!("─── Phase 2: Degrading System ───");
146
147    let mut degrading_kiln = Kiln::new(
148        ThermalProfile::fast_cooling()
149    );
150
151    // Batches where degradation ramps up
152    let degradation_levels = [0.2, 0.5, 0.9, 1.5];
153    for (i, &degradation) in degradation_levels.iter().enumerate() {
154        let batch_id = (5 + i) as u32;
155        // latency increases with degradation
156        let base_latency = 10.0 + degradation * 50.0;
157
158        let events = simulate_batch(batch_id, batch_size as u32, base_latency, degradation);
159        for event in events {
160            degrading_kiln.fire_and_record(event).unwrap();
161        }
162
163        let elapsed = start.elapsed();
164        println!("  Batch {}/{} [degradation={:.1}x] fired (latency baseline: {:.0}ms, {:.0}ms total)",
165                 batch_id, num_batches, degradation, base_latency, elapsed.as_millis());
166    }
167
168    let degrading_patterns = degrading_kiln.cool();
169    println!("\n  Degrading system patterns ({} detected):", degrading_patterns.len());
170    for p in &degrading_patterns {
171        println!("    [{:?}] {} (conf: {:.2})", p.kind(), p.description(), p.confidence());
172    }
173
174    // JSD shift (distribution shape changes)
175    let jsd_shifts = degrading_kiln.jsd_shift(10);
176    println!("    JSD shifts (distribution shape changes):");
177    for (name, shift) in &jsd_shifts[..jsd_shifts.len().min(5)] {
178        println!("      {} → JSD = {:.4}", name, shift);
179    }
180
181    // Permutation entropy (temporal structure)
182    let pes = degrading_kiln.permutation_entropies(4);
183    println!("    Permutation entropies (temporal structure):");
184    for (name, pe) in &pes {
185        println!("      {} → PE = {:.4}", name, pe);
186    }
187
188    println!();
189
190    // Phase 3: Conservation law test — records in = records out should be violated
191    // as errors increase
192    println!("─── Phase 3: Conservation Law Verification ───");
193    let mut conservation_kiln = Kiln::new(
194        ThermalProfile::fast_cooling()
195    );
196
197    // Force records_in = records_out for first 3 batches (healthy conservation)
198    for batch_id in 1..=3 {
199        let event = ProcessedEvent {
200            event_id: batch_id as u64,
201            batch_id: batch_id as u32,
202            processing_time_ms: 10.0,
203            throughput: 100.0,
204            memory_mb: 128.0,
205            error_rate: 0.01,
206            records_in: 1000.0,
207            records_out: 995.0,  // nearly conserved
208            cpu_temp_c: 65.0,
209            latency_p99_ms: 25.0,
210            consumer_lag: 10.0,
211            gc_pause_ms: 5.0,
212        };
213        conservation_kiln.fire_and_record(event).unwrap();
214    }
215
216    // Force violation of records conservation (errors spike)
217    for batch_id in 4..=6 {
218        let event = ProcessedEvent {
219            event_id: batch_id as u64,
220            batch_id: batch_id as u32,
221            processing_time_ms: 10.0 + batch_id as f64 * 10.0,
222            throughput: 50.0,
223            memory_mb: 256.0,
224            error_rate: 0.3,
225            records_in: 1000.0,
226            records_out: 700.0,  // 30% loss — conservation violated
227            cpu_temp_c: 80.0,
228            latency_p99_ms: 100.0,
229            consumer_lag: 500.0,
230            gc_pause_ms: 20.0,
231        };
232        conservation_kiln.fire_and_record(event).unwrap();
233    }
234
235    let conservation_patterns = conservation_kiln.cool();
236    println!("  Conservation-specific patterns ({} detected):", conservation_patterns.len());
237    for p in &conservation_patterns {
238        println!("    [{:?}] {} (conf: {:.2})", p.kind(), p.description(), p.confidence());
239    }
240
241    // MI matrix to show nonlinear dependencies
242    let mi = conservation_kiln.mi_matrix(8);
243    println!("  Mutual Information matrix (8 bins):");
244    let metric_names = ["processing_time_ms", "error_rate", "records_in", "records_out", "memory_mb"];
245    for (i, name_i) in metric_names.iter().enumerate() {
246        for (j, name_j) in metric_names.iter().enumerate() {
247            if i == j {
248                println!("    I({:25}; {:25}) = H({})", name_i, name_j, name_i);
249            } else {
250                println!("    I({:25}; {:25}) = {:.4} bits", name_i, name_j, mi[i][j]);
251            }
252        }
253    }
254
255    println!();
256    println!("───────────────────────────────────────────────────────────────");
257    println!("  SUMMARY");
258    println!("───────────────────────────────────────────────────────────────\n");
259
260    // Degradation detection analysis
261    println!("  Degradation Metrics:");
262    let pt = degrading_patterns.iter().filter(|p| matches!(p.kind(), crackle_runtime::PatternKind::PhaseTransition));
263    let pt_count = pt.count();
264    println!("    Phase transitions detected in degraded system: {} alerts",
265             pt_count);
266
267    let corr = degrading_patterns.iter().filter(|p| matches!(p.kind(), crackle_runtime::PatternKind::Correlation));
268    let corr_count = corr.count();
269    println!("    Correlations in degraded system: {} pairs", corr_count);
270
271    let cons = degrading_patterns.iter().filter(|p| matches!(p.kind(), crackle_runtime::PatternKind::Conservation));
272    let cons_count = cons.count();
273    println!("    Conservation laws in degraded system: {} found", cons_count);
274
275    let clust = degrading_patterns.iter().filter(|p| matches!(p.kind(), crackle_runtime::PatternKind::Clustering));
276    let clust_count = clust.count();
277    println!("    Clusters in degraded system: {} groups", clust_count);
278
279    println!();
280    let total_duration = start.elapsed();
281    println!("  Total test duration: {:.2}s", total_duration.as_secs_f64());
282    println!("  Events processed: {}", total_events);
283    println!("  Avg throughput: {:.0} events/s",
284             total_events as f64 / total_duration.as_secs_f64());
285}
Source

pub fn description(&self) -> &str

Human-readable description of the pattern.

Examples found in repository?
examples/basic.rs (line 44)
29fn main() {
30    let mut kiln = Kiln::new(ThermalProfile::fast_cooling());
31
32        kiln.fire_and_record(NumberTask { value: 2.0, name: "a".into() }).unwrap();
33    kiln.fire_and_record(NumberTask { value: 2.1, name: "b".into() }).unwrap();
34    kiln.fire_and_record(NumberTask { value: 9.8, name: "c".into() }).unwrap();
35    kiln.fire_and_record(NumberTask { value: 10.0, name: "d".into() }).unwrap();
36    kiln.fire_and_record(NumberTask { value: 2.2, name: "e".into() }).unwrap();
37
38    println!("Tasks in kiln: {}", kiln.task_count());
39
40    let patterns = kiln.cool();
41    println!("\nDetected {} pattern(s):\n", patterns.len());
42
43    for p in &patterns {
44        println!("[{}] {}", p.kind(), p.description());
45        println!("  confidence: {:.2}", p.confidence());
46        println!("  tasks: {:?}\n", p.involved_tasks());
47    }
48}
More examples
Hide additional examples
examples/ci_patterns.rs (line 47)
30fn main() {
31    let mut kiln = Kiln::new(ThermalProfile::default());
32
33    // Normal builds
34    kiln.fire_and_record(CiBuild { duration_secs: 45.0, test_count: 200.0, branch: "feature/auth".into() }).unwrap();
35    kiln.fire_and_record(CiBuild { duration_secs: 42.0, test_count: 195.0, branch: "fix/typo".into() }).unwrap();
36    kiln.fire_and_record(CiBuild { duration_secs: 48.0, test_count: 210.0, branch: "feature/ui".into() }).unwrap();
37
38    // Something changed — builds got slower
39    kiln.fire_and_record(CiBuild { duration_secs: 95.0, test_count: 200.0, branch: "feature/cache".into() }).unwrap();
40    kiln.fire_and_record(CiBuild { duration_secs: 102.0, test_count: 198.0, branch: "chore/deps".into() }).unwrap();
41
42    let patterns = kiln.cool();
43    println!("CI Build Pattern Analysis");
44    println!("=========================\n");
45
46    for p in &patterns {
47        println!("[{}] {}", p.kind().to_string().to_uppercase(), p.description());
48        println!("  confidence: {:.2}", p.confidence());
49        println!("  branches: {:?}\n", p.involved_tasks());
50    }
51
52    // Check for phase transition in build duration
53    let phase_shifts: Vec<_> = patterns.iter()
54        .filter(|p| format!("{}", p.kind()) == "phase transition")
55        .collect();
56
57    if !phase_shifts.is_empty() {
58        println!("⚠️  Build duration shifted significantly — investigate recent changes!");
59    }
60}
examples/api_monitoring.rs (line 54)
32fn main() {
33    let mut kiln = Kiln::new(ThermalProfile::default());
34
35    // /api/users — fast, small responses
36    kiln.fire_and_record(ApiRequest { endpoint: "GET /api/users".into(), latency_ms: 45.0, status: 200, response_bytes: 1200.0 }).unwrap();
37    kiln.fire_and_record(ApiRequest { endpoint: "GET /api/users".into(), latency_ms: 48.0, status: 200, response_bytes: 1150.0 }).unwrap();
38    kiln.fire_and_record(ApiRequest { endpoint: "GET /api/users".into(), latency_ms: 52.0, status: 200, response_bytes: 1300.0 }).unwrap();
39
40    // /api/reports — slow, large responses (correlated with bytes)
41    kiln.fire_and_record(ApiRequest { endpoint: "GET /api/reports".into(), latency_ms: 350.0, status: 200, response_bytes: 55000.0 }).unwrap();
42    kiln.fire_and_record(ApiRequest { endpoint: "GET /api/reports".into(), latency_ms: 380.0, status: 200, response_bytes: 62000.0 }).unwrap();
43
44    // /api/health — tiny, always fast (conservation candidate)
45    kiln.fire_and_record(ApiRequest { endpoint: "GET /api/health".into(), latency_ms: 3.0, status: 200, response_bytes: 15.0 }).unwrap();
46    kiln.fire_and_record(ApiRequest { endpoint: "GET /api/health".into(), latency_ms: 4.0, status: 200, response_bytes: 15.0 }).unwrap();
47
48    let patterns = kiln.cool();
49    println!("API Monitoring — Pattern Report");
50    println!("================================\n");
51    println!("{} patterns detected:\n", patterns.len());
52
53    for p in &patterns {
54        println!("[{}] {}", p.kind(), p.description());
55        println!("  confidence: {:.2}", p.confidence());
56        if !p.involved_tasks().is_empty() {
57            println!("  endpoints: {:?}", p.involved_tasks());
58        }
59        println!();
60    }
61
62    // Highlight correlations between latency and response size
63    let correlations: Vec<_> = patterns.iter()
64        .filter(|p| format!("{}", p.kind()) == "correlation")
65        .collect();
66
67    if !correlations.is_empty() {
68        println!("📊 Latency and response size are correlated — consider pagination or caching.");
69    }
70}
examples/event_stream_processor.rs (line 133)
98fn main() {
99    let total_events = 1000;
100    let batch_size = 100;
101    let num_batches = total_events / batch_size;
102
103    println!("═══════════════════════════════════════════════════════════════");
104    println!("  CRACKLE-RUNTIME: EVENT STREAM PROCESSOR TEST");
105    println!("═══════════════════════════════════════════════════════════════\n");
106    println!("Processing {} events across {} batches of {}...\n",
107             total_events, num_batches, batch_size);
108
109    let start = Instant::now();
110
111    // Phase 1: Healthy system (batches 1-4)
112    println!("─── Phase 1: Healthy System ───");
113    let mut healthy_kiln = Kiln::new(
114        ThermalProfile::fast_cooling()
115    );
116
117    // Batch 1-4: all healthy, 10ms baseline latency
118    for batch_id in 1..=4 {
119        let events = simulate_batch(batch_id, batch_size as u32, 10.0, 0.05);
120        for event in events {
121            healthy_kiln.fire_and_record(event).unwrap();
122        }
123
124        let elapsed = start.elapsed();
125        println!("  Batch {}/{} fired ({} events, {:.0}ms)",
126                 batch_id, num_batches, batch_size, elapsed.as_millis());
127    }
128
129    // Cool healthy phase
130    let healthy_patterns = healthy_kiln.cool();
131    println!("\n  Healthy system patterns ({} detected):", healthy_patterns.len());
132    for p in &healthy_patterns {
133        println!("    [{:?}] {} (conf: {:.2})", p.kind(), p.description(), p.confidence());
134    }
135    // Also check conservation on records_in/records_out
136    let conservation = healthy_kiln.distribution_shift(10);
137    println!("    Distribution shifts:");
138    for (name, shift) in &conservation[..conservation.len().min(3)] {
139        println!("      {} → KL = {:.4}", name, shift);
140    }
141
142    println!();
143
144    // Phase 2: Degrading system (batches 5-8)
145    println!("─── Phase 2: Degrading System ───");
146
147    let mut degrading_kiln = Kiln::new(
148        ThermalProfile::fast_cooling()
149    );
150
151    // Batches where degradation ramps up
152    let degradation_levels = [0.2, 0.5, 0.9, 1.5];
153    for (i, &degradation) in degradation_levels.iter().enumerate() {
154        let batch_id = (5 + i) as u32;
155        // latency increases with degradation
156        let base_latency = 10.0 + degradation * 50.0;
157
158        let events = simulate_batch(batch_id, batch_size as u32, base_latency, degradation);
159        for event in events {
160            degrading_kiln.fire_and_record(event).unwrap();
161        }
162
163        let elapsed = start.elapsed();
164        println!("  Batch {}/{} [degradation={:.1}x] fired (latency baseline: {:.0}ms, {:.0}ms total)",
165                 batch_id, num_batches, degradation, base_latency, elapsed.as_millis());
166    }
167
168    let degrading_patterns = degrading_kiln.cool();
169    println!("\n  Degrading system patterns ({} detected):", degrading_patterns.len());
170    for p in &degrading_patterns {
171        println!("    [{:?}] {} (conf: {:.2})", p.kind(), p.description(), p.confidence());
172    }
173
174    // JSD shift (distribution shape changes)
175    let jsd_shifts = degrading_kiln.jsd_shift(10);
176    println!("    JSD shifts (distribution shape changes):");
177    for (name, shift) in &jsd_shifts[..jsd_shifts.len().min(5)] {
178        println!("      {} → JSD = {:.4}", name, shift);
179    }
180
181    // Permutation entropy (temporal structure)
182    let pes = degrading_kiln.permutation_entropies(4);
183    println!("    Permutation entropies (temporal structure):");
184    for (name, pe) in &pes {
185        println!("      {} → PE = {:.4}", name, pe);
186    }
187
188    println!();
189
190    // Phase 3: Conservation law test — records in = records out should be violated
191    // as errors increase
192    println!("─── Phase 3: Conservation Law Verification ───");
193    let mut conservation_kiln = Kiln::new(
194        ThermalProfile::fast_cooling()
195    );
196
197    // Force records_in = records_out for first 3 batches (healthy conservation)
198    for batch_id in 1..=3 {
199        let event = ProcessedEvent {
200            event_id: batch_id as u64,
201            batch_id: batch_id as u32,
202            processing_time_ms: 10.0,
203            throughput: 100.0,
204            memory_mb: 128.0,
205            error_rate: 0.01,
206            records_in: 1000.0,
207            records_out: 995.0,  // nearly conserved
208            cpu_temp_c: 65.0,
209            latency_p99_ms: 25.0,
210            consumer_lag: 10.0,
211            gc_pause_ms: 5.0,
212        };
213        conservation_kiln.fire_and_record(event).unwrap();
214    }
215
216    // Force violation of records conservation (errors spike)
217    for batch_id in 4..=6 {
218        let event = ProcessedEvent {
219            event_id: batch_id as u64,
220            batch_id: batch_id as u32,
221            processing_time_ms: 10.0 + batch_id as f64 * 10.0,
222            throughput: 50.0,
223            memory_mb: 256.0,
224            error_rate: 0.3,
225            records_in: 1000.0,
226            records_out: 700.0,  // 30% loss — conservation violated
227            cpu_temp_c: 80.0,
228            latency_p99_ms: 100.0,
229            consumer_lag: 500.0,
230            gc_pause_ms: 20.0,
231        };
232        conservation_kiln.fire_and_record(event).unwrap();
233    }
234
235    let conservation_patterns = conservation_kiln.cool();
236    println!("  Conservation-specific patterns ({} detected):", conservation_patterns.len());
237    for p in &conservation_patterns {
238        println!("    [{:?}] {} (conf: {:.2})", p.kind(), p.description(), p.confidence());
239    }
240
241    // MI matrix to show nonlinear dependencies
242    let mi = conservation_kiln.mi_matrix(8);
243    println!("  Mutual Information matrix (8 bins):");
244    let metric_names = ["processing_time_ms", "error_rate", "records_in", "records_out", "memory_mb"];
245    for (i, name_i) in metric_names.iter().enumerate() {
246        for (j, name_j) in metric_names.iter().enumerate() {
247            if i == j {
248                println!("    I({:25}; {:25}) = H({})", name_i, name_j, name_i);
249            } else {
250                println!("    I({:25}; {:25}) = {:.4} bits", name_i, name_j, mi[i][j]);
251            }
252        }
253    }
254
255    println!();
256    println!("───────────────────────────────────────────────────────────────");
257    println!("  SUMMARY");
258    println!("───────────────────────────────────────────────────────────────\n");
259
260    // Degradation detection analysis
261    println!("  Degradation Metrics:");
262    let pt = degrading_patterns.iter().filter(|p| matches!(p.kind(), crackle_runtime::PatternKind::PhaseTransition));
263    let pt_count = pt.count();
264    println!("    Phase transitions detected in degraded system: {} alerts",
265             pt_count);
266
267    let corr = degrading_patterns.iter().filter(|p| matches!(p.kind(), crackle_runtime::PatternKind::Correlation));
268    let corr_count = corr.count();
269    println!("    Correlations in degraded system: {} pairs", corr_count);
270
271    let cons = degrading_patterns.iter().filter(|p| matches!(p.kind(), crackle_runtime::PatternKind::Conservation));
272    let cons_count = cons.count();
273    println!("    Conservation laws in degraded system: {} found", cons_count);
274
275    let clust = degrading_patterns.iter().filter(|p| matches!(p.kind(), crackle_runtime::PatternKind::Clustering));
276    let clust_count = clust.count();
277    println!("    Clusters in degraded system: {} groups", clust_count);
278
279    println!();
280    let total_duration = start.elapsed();
281    println!("  Total test duration: {:.2}s", total_duration.as_secs_f64());
282    println!("  Events processed: {}", total_events);
283    println!("  Avg throughput: {:.0} events/s",
284             total_events as f64 / total_duration.as_secs_f64());
285}
Source

pub fn involved_tasks(&self) -> &[String]

Labels of tasks involved in this pattern.

Examples found in repository?
examples/basic.rs (line 46)
29fn main() {
30    let mut kiln = Kiln::new(ThermalProfile::fast_cooling());
31
32        kiln.fire_and_record(NumberTask { value: 2.0, name: "a".into() }).unwrap();
33    kiln.fire_and_record(NumberTask { value: 2.1, name: "b".into() }).unwrap();
34    kiln.fire_and_record(NumberTask { value: 9.8, name: "c".into() }).unwrap();
35    kiln.fire_and_record(NumberTask { value: 10.0, name: "d".into() }).unwrap();
36    kiln.fire_and_record(NumberTask { value: 2.2, name: "e".into() }).unwrap();
37
38    println!("Tasks in kiln: {}", kiln.task_count());
39
40    let patterns = kiln.cool();
41    println!("\nDetected {} pattern(s):\n", patterns.len());
42
43    for p in &patterns {
44        println!("[{}] {}", p.kind(), p.description());
45        println!("  confidence: {:.2}", p.confidence());
46        println!("  tasks: {:?}\n", p.involved_tasks());
47    }
48}
More examples
Hide additional examples
examples/ci_patterns.rs (line 49)
30fn main() {
31    let mut kiln = Kiln::new(ThermalProfile::default());
32
33    // Normal builds
34    kiln.fire_and_record(CiBuild { duration_secs: 45.0, test_count: 200.0, branch: "feature/auth".into() }).unwrap();
35    kiln.fire_and_record(CiBuild { duration_secs: 42.0, test_count: 195.0, branch: "fix/typo".into() }).unwrap();
36    kiln.fire_and_record(CiBuild { duration_secs: 48.0, test_count: 210.0, branch: "feature/ui".into() }).unwrap();
37
38    // Something changed — builds got slower
39    kiln.fire_and_record(CiBuild { duration_secs: 95.0, test_count: 200.0, branch: "feature/cache".into() }).unwrap();
40    kiln.fire_and_record(CiBuild { duration_secs: 102.0, test_count: 198.0, branch: "chore/deps".into() }).unwrap();
41
42    let patterns = kiln.cool();
43    println!("CI Build Pattern Analysis");
44    println!("=========================\n");
45
46    for p in &patterns {
47        println!("[{}] {}", p.kind().to_string().to_uppercase(), p.description());
48        println!("  confidence: {:.2}", p.confidence());
49        println!("  branches: {:?}\n", p.involved_tasks());
50    }
51
52    // Check for phase transition in build duration
53    let phase_shifts: Vec<_> = patterns.iter()
54        .filter(|p| format!("{}", p.kind()) == "phase transition")
55        .collect();
56
57    if !phase_shifts.is_empty() {
58        println!("⚠️  Build duration shifted significantly — investigate recent changes!");
59    }
60}
examples/api_monitoring.rs (line 56)
32fn main() {
33    let mut kiln = Kiln::new(ThermalProfile::default());
34
35    // /api/users — fast, small responses
36    kiln.fire_and_record(ApiRequest { endpoint: "GET /api/users".into(), latency_ms: 45.0, status: 200, response_bytes: 1200.0 }).unwrap();
37    kiln.fire_and_record(ApiRequest { endpoint: "GET /api/users".into(), latency_ms: 48.0, status: 200, response_bytes: 1150.0 }).unwrap();
38    kiln.fire_and_record(ApiRequest { endpoint: "GET /api/users".into(), latency_ms: 52.0, status: 200, response_bytes: 1300.0 }).unwrap();
39
40    // /api/reports — slow, large responses (correlated with bytes)
41    kiln.fire_and_record(ApiRequest { endpoint: "GET /api/reports".into(), latency_ms: 350.0, status: 200, response_bytes: 55000.0 }).unwrap();
42    kiln.fire_and_record(ApiRequest { endpoint: "GET /api/reports".into(), latency_ms: 380.0, status: 200, response_bytes: 62000.0 }).unwrap();
43
44    // /api/health — tiny, always fast (conservation candidate)
45    kiln.fire_and_record(ApiRequest { endpoint: "GET /api/health".into(), latency_ms: 3.0, status: 200, response_bytes: 15.0 }).unwrap();
46    kiln.fire_and_record(ApiRequest { endpoint: "GET /api/health".into(), latency_ms: 4.0, status: 200, response_bytes: 15.0 }).unwrap();
47
48    let patterns = kiln.cool();
49    println!("API Monitoring — Pattern Report");
50    println!("================================\n");
51    println!("{} patterns detected:\n", patterns.len());
52
53    for p in &patterns {
54        println!("[{}] {}", p.kind(), p.description());
55        println!("  confidence: {:.2}", p.confidence());
56        if !p.involved_tasks().is_empty() {
57            println!("  endpoints: {:?}", p.involved_tasks());
58        }
59        println!();
60    }
61
62    // Highlight correlations between latency and response size
63    let correlations: Vec<_> = patterns.iter()
64        .filter(|p| format!("{}", p.kind()) == "correlation")
65        .collect();
66
67    if !correlations.is_empty() {
68        println!("📊 Latency and response size are correlated — consider pagination or caching.");
69    }
70}
Source

pub fn confidence(&self) -> f64

Confidence score (0.0 to 1.0).

Examples found in repository?
examples/basic.rs (line 45)
29fn main() {
30    let mut kiln = Kiln::new(ThermalProfile::fast_cooling());
31
32        kiln.fire_and_record(NumberTask { value: 2.0, name: "a".into() }).unwrap();
33    kiln.fire_and_record(NumberTask { value: 2.1, name: "b".into() }).unwrap();
34    kiln.fire_and_record(NumberTask { value: 9.8, name: "c".into() }).unwrap();
35    kiln.fire_and_record(NumberTask { value: 10.0, name: "d".into() }).unwrap();
36    kiln.fire_and_record(NumberTask { value: 2.2, name: "e".into() }).unwrap();
37
38    println!("Tasks in kiln: {}", kiln.task_count());
39
40    let patterns = kiln.cool();
41    println!("\nDetected {} pattern(s):\n", patterns.len());
42
43    for p in &patterns {
44        println!("[{}] {}", p.kind(), p.description());
45        println!("  confidence: {:.2}", p.confidence());
46        println!("  tasks: {:?}\n", p.involved_tasks());
47    }
48}
More examples
Hide additional examples
examples/ci_patterns.rs (line 48)
30fn main() {
31    let mut kiln = Kiln::new(ThermalProfile::default());
32
33    // Normal builds
34    kiln.fire_and_record(CiBuild { duration_secs: 45.0, test_count: 200.0, branch: "feature/auth".into() }).unwrap();
35    kiln.fire_and_record(CiBuild { duration_secs: 42.0, test_count: 195.0, branch: "fix/typo".into() }).unwrap();
36    kiln.fire_and_record(CiBuild { duration_secs: 48.0, test_count: 210.0, branch: "feature/ui".into() }).unwrap();
37
38    // Something changed — builds got slower
39    kiln.fire_and_record(CiBuild { duration_secs: 95.0, test_count: 200.0, branch: "feature/cache".into() }).unwrap();
40    kiln.fire_and_record(CiBuild { duration_secs: 102.0, test_count: 198.0, branch: "chore/deps".into() }).unwrap();
41
42    let patterns = kiln.cool();
43    println!("CI Build Pattern Analysis");
44    println!("=========================\n");
45
46    for p in &patterns {
47        println!("[{}] {}", p.kind().to_string().to_uppercase(), p.description());
48        println!("  confidence: {:.2}", p.confidence());
49        println!("  branches: {:?}\n", p.involved_tasks());
50    }
51
52    // Check for phase transition in build duration
53    let phase_shifts: Vec<_> = patterns.iter()
54        .filter(|p| format!("{}", p.kind()) == "phase transition")
55        .collect();
56
57    if !phase_shifts.is_empty() {
58        println!("⚠️  Build duration shifted significantly — investigate recent changes!");
59    }
60}
examples/api_monitoring.rs (line 55)
32fn main() {
33    let mut kiln = Kiln::new(ThermalProfile::default());
34
35    // /api/users — fast, small responses
36    kiln.fire_and_record(ApiRequest { endpoint: "GET /api/users".into(), latency_ms: 45.0, status: 200, response_bytes: 1200.0 }).unwrap();
37    kiln.fire_and_record(ApiRequest { endpoint: "GET /api/users".into(), latency_ms: 48.0, status: 200, response_bytes: 1150.0 }).unwrap();
38    kiln.fire_and_record(ApiRequest { endpoint: "GET /api/users".into(), latency_ms: 52.0, status: 200, response_bytes: 1300.0 }).unwrap();
39
40    // /api/reports — slow, large responses (correlated with bytes)
41    kiln.fire_and_record(ApiRequest { endpoint: "GET /api/reports".into(), latency_ms: 350.0, status: 200, response_bytes: 55000.0 }).unwrap();
42    kiln.fire_and_record(ApiRequest { endpoint: "GET /api/reports".into(), latency_ms: 380.0, status: 200, response_bytes: 62000.0 }).unwrap();
43
44    // /api/health — tiny, always fast (conservation candidate)
45    kiln.fire_and_record(ApiRequest { endpoint: "GET /api/health".into(), latency_ms: 3.0, status: 200, response_bytes: 15.0 }).unwrap();
46    kiln.fire_and_record(ApiRequest { endpoint: "GET /api/health".into(), latency_ms: 4.0, status: 200, response_bytes: 15.0 }).unwrap();
47
48    let patterns = kiln.cool();
49    println!("API Monitoring — Pattern Report");
50    println!("================================\n");
51    println!("{} patterns detected:\n", patterns.len());
52
53    for p in &patterns {
54        println!("[{}] {}", p.kind(), p.description());
55        println!("  confidence: {:.2}", p.confidence());
56        if !p.involved_tasks().is_empty() {
57            println!("  endpoints: {:?}", p.involved_tasks());
58        }
59        println!();
60    }
61
62    // Highlight correlations between latency and response size
63    let correlations: Vec<_> = patterns.iter()
64        .filter(|p| format!("{}", p.kind()) == "correlation")
65        .collect();
66
67    if !correlations.is_empty() {
68        println!("📊 Latency and response size are correlated — consider pagination or caching.");
69    }
70}
examples/event_stream_processor.rs (line 133)
98fn main() {
99    let total_events = 1000;
100    let batch_size = 100;
101    let num_batches = total_events / batch_size;
102
103    println!("═══════════════════════════════════════════════════════════════");
104    println!("  CRACKLE-RUNTIME: EVENT STREAM PROCESSOR TEST");
105    println!("═══════════════════════════════════════════════════════════════\n");
106    println!("Processing {} events across {} batches of {}...\n",
107             total_events, num_batches, batch_size);
108
109    let start = Instant::now();
110
111    // Phase 1: Healthy system (batches 1-4)
112    println!("─── Phase 1: Healthy System ───");
113    let mut healthy_kiln = Kiln::new(
114        ThermalProfile::fast_cooling()
115    );
116
117    // Batch 1-4: all healthy, 10ms baseline latency
118    for batch_id in 1..=4 {
119        let events = simulate_batch(batch_id, batch_size as u32, 10.0, 0.05);
120        for event in events {
121            healthy_kiln.fire_and_record(event).unwrap();
122        }
123
124        let elapsed = start.elapsed();
125        println!("  Batch {}/{} fired ({} events, {:.0}ms)",
126                 batch_id, num_batches, batch_size, elapsed.as_millis());
127    }
128
129    // Cool healthy phase
130    let healthy_patterns = healthy_kiln.cool();
131    println!("\n  Healthy system patterns ({} detected):", healthy_patterns.len());
132    for p in &healthy_patterns {
133        println!("    [{:?}] {} (conf: {:.2})", p.kind(), p.description(), p.confidence());
134    }
135    // Also check conservation on records_in/records_out
136    let conservation = healthy_kiln.distribution_shift(10);
137    println!("    Distribution shifts:");
138    for (name, shift) in &conservation[..conservation.len().min(3)] {
139        println!("      {} → KL = {:.4}", name, shift);
140    }
141
142    println!();
143
144    // Phase 2: Degrading system (batches 5-8)
145    println!("─── Phase 2: Degrading System ───");
146
147    let mut degrading_kiln = Kiln::new(
148        ThermalProfile::fast_cooling()
149    );
150
151    // Batches where degradation ramps up
152    let degradation_levels = [0.2, 0.5, 0.9, 1.5];
153    for (i, &degradation) in degradation_levels.iter().enumerate() {
154        let batch_id = (5 + i) as u32;
155        // latency increases with degradation
156        let base_latency = 10.0 + degradation * 50.0;
157
158        let events = simulate_batch(batch_id, batch_size as u32, base_latency, degradation);
159        for event in events {
160            degrading_kiln.fire_and_record(event).unwrap();
161        }
162
163        let elapsed = start.elapsed();
164        println!("  Batch {}/{} [degradation={:.1}x] fired (latency baseline: {:.0}ms, {:.0}ms total)",
165                 batch_id, num_batches, degradation, base_latency, elapsed.as_millis());
166    }
167
168    let degrading_patterns = degrading_kiln.cool();
169    println!("\n  Degrading system patterns ({} detected):", degrading_patterns.len());
170    for p in &degrading_patterns {
171        println!("    [{:?}] {} (conf: {:.2})", p.kind(), p.description(), p.confidence());
172    }
173
174    // JSD shift (distribution shape changes)
175    let jsd_shifts = degrading_kiln.jsd_shift(10);
176    println!("    JSD shifts (distribution shape changes):");
177    for (name, shift) in &jsd_shifts[..jsd_shifts.len().min(5)] {
178        println!("      {} → JSD = {:.4}", name, shift);
179    }
180
181    // Permutation entropy (temporal structure)
182    let pes = degrading_kiln.permutation_entropies(4);
183    println!("    Permutation entropies (temporal structure):");
184    for (name, pe) in &pes {
185        println!("      {} → PE = {:.4}", name, pe);
186    }
187
188    println!();
189
190    // Phase 3: Conservation law test — records in = records out should be violated
191    // as errors increase
192    println!("─── Phase 3: Conservation Law Verification ───");
193    let mut conservation_kiln = Kiln::new(
194        ThermalProfile::fast_cooling()
195    );
196
197    // Force records_in = records_out for first 3 batches (healthy conservation)
198    for batch_id in 1..=3 {
199        let event = ProcessedEvent {
200            event_id: batch_id as u64,
201            batch_id: batch_id as u32,
202            processing_time_ms: 10.0,
203            throughput: 100.0,
204            memory_mb: 128.0,
205            error_rate: 0.01,
206            records_in: 1000.0,
207            records_out: 995.0,  // nearly conserved
208            cpu_temp_c: 65.0,
209            latency_p99_ms: 25.0,
210            consumer_lag: 10.0,
211            gc_pause_ms: 5.0,
212        };
213        conservation_kiln.fire_and_record(event).unwrap();
214    }
215
216    // Force violation of records conservation (errors spike)
217    for batch_id in 4..=6 {
218        let event = ProcessedEvent {
219            event_id: batch_id as u64,
220            batch_id: batch_id as u32,
221            processing_time_ms: 10.0 + batch_id as f64 * 10.0,
222            throughput: 50.0,
223            memory_mb: 256.0,
224            error_rate: 0.3,
225            records_in: 1000.0,
226            records_out: 700.0,  // 30% loss — conservation violated
227            cpu_temp_c: 80.0,
228            latency_p99_ms: 100.0,
229            consumer_lag: 500.0,
230            gc_pause_ms: 20.0,
231        };
232        conservation_kiln.fire_and_record(event).unwrap();
233    }
234
235    let conservation_patterns = conservation_kiln.cool();
236    println!("  Conservation-specific patterns ({} detected):", conservation_patterns.len());
237    for p in &conservation_patterns {
238        println!("    [{:?}] {} (conf: {:.2})", p.kind(), p.description(), p.confidence());
239    }
240
241    // MI matrix to show nonlinear dependencies
242    let mi = conservation_kiln.mi_matrix(8);
243    println!("  Mutual Information matrix (8 bins):");
244    let metric_names = ["processing_time_ms", "error_rate", "records_in", "records_out", "memory_mb"];
245    for (i, name_i) in metric_names.iter().enumerate() {
246        for (j, name_j) in metric_names.iter().enumerate() {
247            if i == j {
248                println!("    I({:25}; {:25}) = H({})", name_i, name_j, name_i);
249            } else {
250                println!("    I({:25}; {:25}) = {:.4} bits", name_i, name_j, mi[i][j]);
251            }
252        }
253    }
254
255    println!();
256    println!("───────────────────────────────────────────────────────────────");
257    println!("  SUMMARY");
258    println!("───────────────────────────────────────────────────────────────\n");
259
260    // Degradation detection analysis
261    println!("  Degradation Metrics:");
262    let pt = degrading_patterns.iter().filter(|p| matches!(p.kind(), crackle_runtime::PatternKind::PhaseTransition));
263    let pt_count = pt.count();
264    println!("    Phase transitions detected in degraded system: {} alerts",
265             pt_count);
266
267    let corr = degrading_patterns.iter().filter(|p| matches!(p.kind(), crackle_runtime::PatternKind::Correlation));
268    let corr_count = corr.count();
269    println!("    Correlations in degraded system: {} pairs", corr_count);
270
271    let cons = degrading_patterns.iter().filter(|p| matches!(p.kind(), crackle_runtime::PatternKind::Conservation));
272    let cons_count = cons.count();
273    println!("    Conservation laws in degraded system: {} found", cons_count);
274
275    let clust = degrading_patterns.iter().filter(|p| matches!(p.kind(), crackle_runtime::PatternKind::Clustering));
276    let clust_count = clust.count();
277    println!("    Clusters in degraded system: {} groups", clust_count);
278
279    println!();
280    let total_duration = start.elapsed();
281    println!("  Total test duration: {:.2}s", total_duration.as_secs_f64());
282    println!("  Events processed: {}", total_events);
283    println!("  Avg throughput: {:.0} events/s",
284             total_events as f64 / total_duration.as_secs_f64());
285}
Source

pub fn metrics(&self) -> &[(String, f64)]

Additional metrics associated with this pattern.

Source

pub fn with_metric(self, name: impl Into<String>, value: f64) -> Self

Add a metric to this pattern.

Source

pub fn with_metrics(self, metrics: Vec<(String, f64)>) -> Self

Create a pattern with additional metrics.

Trait Implementations§

Source§

impl Clone for CracklePattern

Source§

fn clone(&self) -> CracklePattern

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for CracklePattern

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.