decision_agent 0.3.0 โ†’ 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (115) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +272 -7
  3. data/lib/decision_agent/agent.rb +72 -1
  4. data/lib/decision_agent/context.rb +1 -0
  5. data/lib/decision_agent/data_enrichment/cache/memory_adapter.rb +86 -0
  6. data/lib/decision_agent/data_enrichment/cache_adapter.rb +49 -0
  7. data/lib/decision_agent/data_enrichment/circuit_breaker.rb +135 -0
  8. data/lib/decision_agent/data_enrichment/client.rb +220 -0
  9. data/lib/decision_agent/data_enrichment/config.rb +78 -0
  10. data/lib/decision_agent/data_enrichment/errors.rb +36 -0
  11. data/lib/decision_agent/decision.rb +102 -2
  12. data/lib/decision_agent/dmn/feel/evaluator.rb +28 -6
  13. data/lib/decision_agent/dsl/condition_evaluator.rb +982 -839
  14. data/lib/decision_agent/dsl/schema_validator.rb +51 -13
  15. data/lib/decision_agent/evaluators/dmn_evaluator.rb +106 -19
  16. data/lib/decision_agent/evaluators/json_rule_evaluator.rb +69 -9
  17. data/lib/decision_agent/explainability/condition_trace.rb +83 -0
  18. data/lib/decision_agent/explainability/explainability_result.rb +52 -0
  19. data/lib/decision_agent/explainability/rule_trace.rb +39 -0
  20. data/lib/decision_agent/explainability/trace_collector.rb +24 -0
  21. data/lib/decision_agent/monitoring/alert_manager.rb +5 -1
  22. data/lib/decision_agent/simulation/errors.rb +18 -0
  23. data/lib/decision_agent/simulation/impact_analyzer.rb +498 -0
  24. data/lib/decision_agent/simulation/monte_carlo_simulator.rb +635 -0
  25. data/lib/decision_agent/simulation/replay_engine.rb +486 -0
  26. data/lib/decision_agent/simulation/scenario_engine.rb +318 -0
  27. data/lib/decision_agent/simulation/scenario_library.rb +163 -0
  28. data/lib/decision_agent/simulation/shadow_test_engine.rb +287 -0
  29. data/lib/decision_agent/simulation/what_if_analyzer.rb +1002 -0
  30. data/lib/decision_agent/simulation.rb +17 -0
  31. data/lib/decision_agent/version.rb +1 -1
  32. data/lib/decision_agent/versioning/activerecord_adapter.rb +23 -8
  33. data/lib/decision_agent/web/public/app.js +119 -0
  34. data/lib/decision_agent/web/public/index.html +49 -0
  35. data/lib/decision_agent/web/public/simulation.html +130 -0
  36. data/lib/decision_agent/web/public/simulation_impact.html +478 -0
  37. data/lib/decision_agent/web/public/simulation_replay.html +551 -0
  38. data/lib/decision_agent/web/public/simulation_shadow.html +546 -0
  39. data/lib/decision_agent/web/public/simulation_whatif.html +532 -0
  40. data/lib/decision_agent/web/public/styles.css +65 -0
  41. data/lib/decision_agent/web/server.rb +594 -23
  42. data/lib/decision_agent.rb +60 -2
  43. metadata +53 -73
  44. data/spec/ab_testing/ab_test_assignment_spec.rb +0 -253
  45. data/spec/ab_testing/ab_test_manager_spec.rb +0 -612
  46. data/spec/ab_testing/ab_test_spec.rb +0 -270
  47. data/spec/ab_testing/ab_testing_agent_spec.rb +0 -655
  48. data/spec/ab_testing/storage/adapter_spec.rb +0 -64
  49. data/spec/ab_testing/storage/memory_adapter_spec.rb +0 -485
  50. data/spec/activerecord_thread_safety_spec.rb +0 -553
  51. data/spec/advanced_operators_spec.rb +0 -3150
  52. data/spec/agent_spec.rb +0 -289
  53. data/spec/api_contract_spec.rb +0 -430
  54. data/spec/audit_adapters_spec.rb +0 -92
  55. data/spec/auth/access_audit_logger_spec.rb +0 -394
  56. data/spec/auth/authenticator_spec.rb +0 -112
  57. data/spec/auth/password_reset_spec.rb +0 -294
  58. data/spec/auth/permission_checker_spec.rb +0 -207
  59. data/spec/auth/permission_spec.rb +0 -73
  60. data/spec/auth/rbac_adapter_spec.rb +0 -778
  61. data/spec/auth/rbac_config_spec.rb +0 -82
  62. data/spec/auth/role_spec.rb +0 -51
  63. data/spec/auth/session_manager_spec.rb +0 -172
  64. data/spec/auth/session_spec.rb +0 -112
  65. data/spec/auth/user_spec.rb +0 -130
  66. data/spec/comprehensive_edge_cases_spec.rb +0 -1777
  67. data/spec/context_spec.rb +0 -127
  68. data/spec/decision_agent_spec.rb +0 -96
  69. data/spec/decision_spec.rb +0 -423
  70. data/spec/dmn/decision_graph_spec.rb +0 -282
  71. data/spec/dmn/decision_tree_spec.rb +0 -203
  72. data/spec/dmn/feel/errors_spec.rb +0 -18
  73. data/spec/dmn/feel/functions_spec.rb +0 -400
  74. data/spec/dmn/feel/simple_parser_spec.rb +0 -274
  75. data/spec/dmn/feel/types_spec.rb +0 -176
  76. data/spec/dmn/feel_parser_spec.rb +0 -489
  77. data/spec/dmn/hit_policy_spec.rb +0 -202
  78. data/spec/dmn/integration_spec.rb +0 -226
  79. data/spec/dsl/condition_evaluator_spec.rb +0 -774
  80. data/spec/dsl_validation_spec.rb +0 -648
  81. data/spec/edge_cases_spec.rb +0 -353
  82. data/spec/evaluation_spec.rb +0 -364
  83. data/spec/evaluation_validator_spec.rb +0 -165
  84. data/spec/examples/feedback_aware_evaluator_spec.rb +0 -460
  85. data/spec/examples.txt +0 -1909
  86. data/spec/fixtures/dmn/complex_decision.dmn +0 -81
  87. data/spec/fixtures/dmn/invalid_structure.dmn +0 -31
  88. data/spec/fixtures/dmn/simple_decision.dmn +0 -40
  89. data/spec/issue_verification_spec.rb +0 -759
  90. data/spec/json_rule_evaluator_spec.rb +0 -587
  91. data/spec/monitoring/alert_manager_spec.rb +0 -378
  92. data/spec/monitoring/metrics_collector_spec.rb +0 -501
  93. data/spec/monitoring/monitored_agent_spec.rb +0 -225
  94. data/spec/monitoring/prometheus_exporter_spec.rb +0 -242
  95. data/spec/monitoring/storage/activerecord_adapter_spec.rb +0 -498
  96. data/spec/monitoring/storage/base_adapter_spec.rb +0 -61
  97. data/spec/monitoring/storage/memory_adapter_spec.rb +0 -247
  98. data/spec/performance_optimizations_spec.rb +0 -493
  99. data/spec/replay_edge_cases_spec.rb +0 -699
  100. data/spec/replay_spec.rb +0 -210
  101. data/spec/rfc8785_canonicalization_spec.rb +0 -215
  102. data/spec/scoring_spec.rb +0 -225
  103. data/spec/spec_helper.rb +0 -60
  104. data/spec/testing/batch_test_importer_spec.rb +0 -693
  105. data/spec/testing/batch_test_runner_spec.rb +0 -307
  106. data/spec/testing/test_coverage_analyzer_spec.rb +0 -292
  107. data/spec/testing/test_result_comparator_spec.rb +0 -392
  108. data/spec/testing/test_scenario_spec.rb +0 -113
  109. data/spec/thread_safety_spec.rb +0 -490
  110. data/spec/thread_safety_spec.rb.broken +0 -878
  111. data/spec/versioning/adapter_spec.rb +0 -156
  112. data/spec/versioning_spec.rb +0 -1030
  113. data/spec/web/middleware/auth_middleware_spec.rb +0 -133
  114. data/spec/web/middleware/permission_middleware_spec.rb +0 -247
  115. data/spec/web_ui_rack_spec.rb +0 -2134
@@ -0,0 +1,17 @@
1
+ # Simulation and What-If Analysis module
2
+ # Provides tools for scenario testing, historical replay, impact analysis, shadow testing, and Monte Carlo simulation
3
+
4
+ require_relative "simulation/errors"
5
+ require_relative "simulation/replay_engine"
6
+ require_relative "simulation/what_if_analyzer"
7
+ require_relative "simulation/impact_analyzer"
8
+ require_relative "simulation/shadow_test_engine"
9
+ require_relative "simulation/scenario_engine"
10
+ require_relative "simulation/scenario_library"
11
+ require_relative "simulation/monte_carlo_simulator"
12
+
13
+ module DecisionAgent
14
+ module Simulation
15
+ # Main entry point for simulation features
16
+ end
17
+ end
@@ -3,7 +3,7 @@ module DecisionAgent
3
3
  # MAJOR: Incremented for incompatible API changes
4
4
  # MINOR: Incremented for backward-compatible functionality additions
5
5
  # PATCH: Incremented for backward-compatible bug fixes
6
- VERSION = "0.3.0".freeze
6
+ VERSION = "1.0.1".freeze
7
7
 
8
8
  # Validate version format (semantic versioning)
9
9
  unless VERSION.match?(/\A\d+\.\d+\.\d+(-[a-zA-Z0-9-]+(\.[a-zA-Z0-9-]+)*)?(\+[a-zA-Z0-9-]+(\.[a-zA-Z0-9-]+)*)?\z/)
@@ -33,10 +33,10 @@ module DecisionAgent
33
33
  next_version_number = last_version ? last_version.version_number + 1 : 1
34
34
 
35
35
  # Deactivate previous active versions
36
- # Use update! instead of update_all to trigger validations
37
- rule_version_class.where(rule_id: rule_id, status: "active").find_each do |v|
38
- v.update!(status: "archived")
39
- end
36
+ # Use update_all for better concurrency (avoids SQLite locking issues)
37
+ # Status "archived" is valid, so no need to trigger validations
38
+ rule_version_class.where(rule_id: rule_id, status: "active")
39
+ .update_all(status: "archived")
40
40
 
41
41
  # Create new version
42
42
  version = rule_version_class.create!(
@@ -87,12 +87,11 @@ module DecisionAgent
87
87
 
88
88
  # Deactivate all other versions for this rule within the same transaction
89
89
  # The lock ensures only one thread can perform this operation at a time
90
- # Use update! instead of update_all to trigger validations
90
+ # Use update_all for better concurrency (avoids SQLite locking issues)
91
+ # Status "archived" is valid, so no need to trigger validations
91
92
  rule_version_class.where(rule_id: version.rule_id, status: "active")
92
93
  .where.not(id: version_id)
93
- .find_each do |v|
94
- v.update!(status: "archived")
95
- end
94
+ .update_all(status: "archived")
96
95
 
97
96
  # Activate this version
98
97
  version.update!(status: "active")
@@ -101,6 +100,22 @@ module DecisionAgent
101
100
  serialize_version(version)
102
101
  end
103
102
 
103
+ def delete_version(version_id:)
104
+ version = rule_version_class.find_by(id: version_id)
105
+
106
+ # Version not found
107
+ raise DecisionAgent::NotFoundError, "Version not found: #{version_id}" unless version
108
+
109
+ # Prevent deletion of active versions
110
+ raise DecisionAgent::ValidationError, "Cannot delete active version. Please activate another version first." if version.status == "active"
111
+
112
+ # Delete the version
113
+ version.destroy
114
+ true
115
+ rescue ActiveRecord::RecordNotFound
116
+ raise DecisionAgent::NotFoundError, "Version not found: #{version_id}"
117
+ end
118
+
104
119
  private
105
120
 
106
121
  def rule_version_class
@@ -84,6 +84,7 @@ class RuleBuilder {
84
84
 
85
85
  // Actions
86
86
  document.getElementById('validateBtn').addEventListener('click', () => this.validateRules());
87
+ document.getElementById('testRuleBtn').addEventListener('click', () => this.openTestRuleModal());
87
88
  document.getElementById('clearBtn').addEventListener('click', () => this.clearAll());
88
89
  document.getElementById('loadExampleBtn').addEventListener('click', () => this.loadExample());
89
90
 
@@ -101,6 +102,11 @@ class RuleBuilder {
101
102
  document.getElementById('closeCompareBtn').addEventListener('click', () => this.closeCompareModal());
102
103
  document.getElementById('closeCompareModalBtn').addEventListener('click', () => this.closeCompareModal());
103
104
 
105
+ // Test Rule
106
+ document.getElementById('runTestBtn').addEventListener('click', () => this.runTest());
107
+ document.getElementById('closeTestRuleBtn').addEventListener('click', () => this.closeTestRuleModal());
108
+ document.getElementById('closeTestRuleModalBtn').addEventListener('click', () => this.closeTestRuleModal());
109
+
104
110
  // Modal close on outside click
105
111
  document.getElementById('ruleModal').addEventListener('click', (e) => {
106
112
  if (e.target.id === 'ruleModal') {
@@ -1134,6 +1140,119 @@ class RuleBuilder {
1134
1140
  document.getElementById('compareVersionsModal').classList.add('hidden');
1135
1141
  }
1136
1142
 
1143
+ getRulesJSON() {
1144
+ const version = document.getElementById('rulesetVersion').value || '1.0';
1145
+ const ruleset = document.getElementById('rulesetName').value || 'my_ruleset';
1146
+ const rules = this.rules.map(rule => ({
1147
+ id: rule.id,
1148
+ if: rule.if,
1149
+ then: rule.then
1150
+ }));
1151
+
1152
+ return {
1153
+ version: version,
1154
+ ruleset: ruleset,
1155
+ rules: rules
1156
+ };
1157
+ }
1158
+
1159
+ openTestRuleModal() {
1160
+ document.getElementById('testRuleModal').classList.remove('hidden');
1161
+ document.getElementById('testContext').value = '{}';
1162
+ document.getElementById('testResults').classList.add('hidden');
1163
+ }
1164
+
1165
+ closeTestRuleModal() {
1166
+ document.getElementById('testRuleModal').classList.add('hidden');
1167
+ }
1168
+
1169
+ async runTest() {
1170
+ const contextText = document.getElementById('testContext').value.trim();
1171
+
1172
+ // Get current rules
1173
+ const rules = this.getRulesJSON();
1174
+
1175
+ if (!rules || !rules.rules || rules.rules.length === 0) {
1176
+ alert('Please add at least one rule before testing');
1177
+ return;
1178
+ }
1179
+
1180
+ let context;
1181
+ try {
1182
+ context = contextText ? JSON.parse(contextText) : {};
1183
+ } catch (e) {
1184
+ alert('Invalid JSON in context field: ' + e.message);
1185
+ return;
1186
+ }
1187
+
1188
+ try {
1189
+ const response = await fetch(`${this.basePath}api/evaluate`, {
1190
+ method: 'POST',
1191
+ headers: this.getAuthHeaders(),
1192
+ body: JSON.stringify({
1193
+ rules: rules,
1194
+ context: context
1195
+ })
1196
+ });
1197
+
1198
+ const data = await response.json();
1199
+
1200
+ if (!response.ok || !data.success) {
1201
+ alert('Test failed: ' + (data.error || 'Unknown error'));
1202
+ return;
1203
+ }
1204
+
1205
+ // Display results
1206
+ const resultsDiv = document.getElementById('testResults');
1207
+ resultsDiv.classList.remove('hidden');
1208
+
1209
+ if (data.decision) {
1210
+ document.getElementById('testDecisionValue').textContent = data.decision;
1211
+ document.getElementById('testConfidenceValue').textContent = (data.confidence || 0).toFixed(3);
1212
+ document.getElementById('testReasonValue').textContent = data.reason || 'N/A';
1213
+
1214
+ // Display explainability
1215
+ const becauseList = document.getElementById('testBecauseList');
1216
+ const failedList = document.getElementById('testFailedList');
1217
+
1218
+ if (data.because && data.because.length > 0) {
1219
+ becauseList.innerHTML = '';
1220
+ data.because.forEach(condition => {
1221
+ const li = document.createElement('li');
1222
+ li.textContent = condition;
1223
+ li.style.color = '#28a745';
1224
+ becauseList.appendChild(li);
1225
+ });
1226
+ document.getElementById('testBecause').style.display = 'block';
1227
+ } else {
1228
+ document.getElementById('testBecause').style.display = 'none';
1229
+ }
1230
+
1231
+ if (data.failed_conditions && data.failed_conditions.length > 0) {
1232
+ failedList.innerHTML = '';
1233
+ data.failed_conditions.forEach(condition => {
1234
+ const li = document.createElement('li');
1235
+ li.textContent = condition;
1236
+ li.style.color = '#dc3545';
1237
+ failedList.appendChild(li);
1238
+ });
1239
+ document.getElementById('testFailedConditions').style.display = 'block';
1240
+ } else {
1241
+ document.getElementById('testFailedConditions').style.display = 'none';
1242
+ }
1243
+
1244
+ document.getElementById('testExplainability').style.display = 'block';
1245
+ } else {
1246
+ document.getElementById('testDecisionValue').textContent = 'No match';
1247
+ document.getElementById('testConfidenceValue').textContent = 'N/A';
1248
+ document.getElementById('testReasonValue').textContent = data.message || 'No rules matched';
1249
+ document.getElementById('testExplainability').style.display = 'none';
1250
+ }
1251
+ } catch (error) {
1252
+ alert('Error running test: ' + error.message);
1253
+ }
1254
+ }
1255
+
1137
1256
  async deleteVersion(versionId) {
1138
1257
  if (!confirm('Are you sure you want to delete this version? This action cannot be undone.')) {
1139
1258
  return;
@@ -13,6 +13,8 @@
13
13
  <p class="subtitle">Visual rule editor for non-technical users</p>
14
14
  <div class="header-links">
15
15
  <a href="/dmn/editor" class="btn btn-link">๐Ÿ“Š DMN Editor</a>
16
+ <a href="/simulation" class="btn btn-link">๐Ÿงช Simulation</a>
17
+ <a href="/testing/batch" class="btn btn-link">๐Ÿ“Š Batch Testing</a>
16
18
  </div>
17
19
  </header>
18
20
 
@@ -51,6 +53,7 @@
51
53
  <!-- Action Buttons -->
52
54
  <div class="actions">
53
55
  <button class="btn btn-success" id="validateBtn">โœ“ Validate Rules</button>
56
+ <button class="btn btn-info" id="testRuleBtn">๐Ÿงช Test Rule</button>
54
57
  <button class="btn btn-primary" id="saveVersionBtn">๐Ÿ’พ Save Version</button>
55
58
  <button class="btn btn-secondary" id="clearBtn">Clear All</button>
56
59
  </div>
@@ -333,6 +336,52 @@
333
336
  </div>
334
337
  </div>
335
338
  </div>
339
+
340
+ <!-- Test Rule Modal -->
341
+ <div id="testRuleModal" class="modal hidden">
342
+ <div class="modal-content modal-large">
343
+ <div class="modal-header">
344
+ <h2>๐Ÿงช Test Rule</h2>
345
+ <button class="close-btn" id="closeTestRuleBtn">&times;</button>
346
+ </div>
347
+ <div class="modal-body">
348
+ <div class="form-group">
349
+ <label for="testContext">Test Context (JSON):</label>
350
+ <textarea id="testContext" class="input" rows="8" placeholder='{"field1": "value1", "field2": 123}'></textarea>
351
+ <small class="form-hint">Enter context data as JSON to test your rules</small>
352
+ </div>
353
+ <div class="actions" style="margin-top: 1rem;">
354
+ <button class="btn btn-primary" id="runTestBtn">Run Test</button>
355
+ </div>
356
+ <div id="testResults" class="test-results hidden" style="margin-top: 2rem;">
357
+ <h3>Test Results</h3>
358
+ <div id="testDecision" class="test-result-item">
359
+ <strong>Decision:</strong> <span id="testDecisionValue">-</span>
360
+ </div>
361
+ <div id="testConfidence" class="test-result-item">
362
+ <strong>Confidence:</strong> <span id="testConfidenceValue">-</span>
363
+ </div>
364
+ <div id="testReason" class="test-result-item">
365
+ <strong>Reason:</strong> <span id="testReasonValue">-</span>
366
+ </div>
367
+ <div id="testExplainability" class="test-explainability" style="margin-top: 1.5rem;">
368
+ <h4>Explainability</h4>
369
+ <div id="testBecause" class="test-because">
370
+ <strong>Because (conditions that led to decision):</strong>
371
+ <ul id="testBecauseList"></ul>
372
+ </div>
373
+ <div id="testFailedConditions" class="test-failed" style="margin-top: 1rem;">
374
+ <strong>Failed Conditions:</strong>
375
+ <ul id="testFailedList"></ul>
376
+ </div>
377
+ </div>
378
+ </div>
379
+ </div>
380
+ <div class="modal-footer">
381
+ <button class="btn btn-secondary" id="closeTestRuleModalBtn">Close</button>
382
+ </div>
383
+ </div>
384
+ </div>
336
385
  </div>
337
386
 
338
387
  <footer class="footer">
@@ -0,0 +1,130 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>DecisionAgent Simulation Dashboard</title>
7
+ <link rel="stylesheet" href="styles.css">
8
+ <style>
9
+ .simulation-dashboard {
10
+ max-width: 1400px;
11
+ margin: 0 auto;
12
+ padding: 20px;
13
+ }
14
+
15
+ .feature-grid {
16
+ display: grid;
17
+ grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
18
+ gap: 20px;
19
+ margin-top: 30px;
20
+ }
21
+
22
+ .feature-card {
23
+ background: var(--panel-bg);
24
+ border-radius: 10px;
25
+ padding: 25px;
26
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
27
+ transition: transform 0.2s, box-shadow 0.2s;
28
+ cursor: pointer;
29
+ text-decoration: none;
30
+ color: inherit;
31
+ display: block;
32
+ }
33
+
34
+ .feature-card:hover {
35
+ transform: translateY(-2px);
36
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.15);
37
+ }
38
+
39
+ .feature-icon {
40
+ font-size: 3rem;
41
+ margin-bottom: 15px;
42
+ }
43
+
44
+ .feature-title {
45
+ font-size: 1.5rem;
46
+ font-weight: 600;
47
+ margin-bottom: 10px;
48
+ color: var(--primary-color);
49
+ }
50
+
51
+ .feature-description {
52
+ color: var(--text-secondary);
53
+ line-height: 1.6;
54
+ }
55
+
56
+ .header-links {
57
+ margin-top: 20px;
58
+ }
59
+
60
+ .header-links a {
61
+ margin-right: 15px;
62
+ text-decoration: none;
63
+ color: var(--primary-color);
64
+ }
65
+ </style>
66
+ </head>
67
+ <body>
68
+ <div class="simulation-dashboard">
69
+ <header>
70
+ <h1>๐Ÿงช DecisionAgent Simulation Dashboard</h1>
71
+ <p class="subtitle">Test rule changes, predict impact, and validate decisions before deployment</p>
72
+ <div class="header-links">
73
+ <a href="/">๐Ÿ  Rule Builder</a>
74
+ <a href="/testing/batch">๐Ÿ“Š Batch Testing</a>
75
+ <a href="/dmn/editor">๐Ÿ“‹ DMN Editor</a>
76
+ </div>
77
+ </header>
78
+
79
+ <div class="feature-grid">
80
+ <a href="/simulation/replay" class="feature-card">
81
+ <div class="feature-icon">๐Ÿ”„</div>
82
+ <div class="feature-title">Historical Replay / Backtesting</div>
83
+ <div class="feature-description">
84
+ Replay historical decisions with different rule versions to see how outcomes would change.
85
+ Compare baseline vs. proposed versions and analyze decision changes.
86
+ </div>
87
+ </a>
88
+
89
+ <a href="/simulation/whatif" class="feature-card">
90
+ <div class="feature-icon">โ“</div>
91
+ <div class="feature-title">What-If Analysis</div>
92
+ <div class="feature-description">
93
+ Simulate different scenarios and analyze how decisions change based on input variations.
94
+ Perform sensitivity analysis to identify which inputs matter most.
95
+ </div>
96
+ </a>
97
+
98
+ <a href="/simulation/impact" class="feature-card">
99
+ <div class="feature-icon">๐Ÿ“Š</div>
100
+ <div class="feature-title">Impact Analysis</div>
101
+ <div class="feature-description">
102
+ Quantify the impact of rule changes before deploying to production.
103
+ Get risk scores, decision distribution changes, and confidence shifts.
104
+ </div>
105
+ </a>
106
+
107
+ <a href="/simulation/shadow" class="feature-card">
108
+ <div class="feature-icon">๐Ÿ‘ป</div>
109
+ <div class="feature-title">Shadow Testing</div>
110
+ <div class="feature-description">
111
+ Compare new rules against production without affecting actual outcomes.
112
+ Test on production traffic with zero impact on real decisions.
113
+ </div>
114
+ </a>
115
+ </div>
116
+
117
+ <div style="margin-top: 40px; padding: 20px; background: var(--panel-bg); border-radius: 10px;">
118
+ <h2>Quick Start</h2>
119
+ <p>Choose a simulation type above to get started:</p>
120
+ <ul style="line-height: 2;">
121
+ <li><strong>Historical Replay:</strong> Upload historical data (CSV/JSON) and replay with different rule versions</li>
122
+ <li><strong>What-If Analysis:</strong> Define scenarios and see how decisions change</li>
123
+ <li><strong>Impact Analysis:</strong> Compare two rule versions to assess change impact</li>
124
+ <li><strong>Shadow Testing:</strong> Test new rules alongside production without affecting outcomes</li>
125
+ </ul>
126
+ </div>
127
+ </div>
128
+ </body>
129
+ </html>
130
+