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.
- checksums.yaml +4 -4
- data/README.md +272 -7
- data/lib/decision_agent/agent.rb +72 -1
- data/lib/decision_agent/context.rb +1 -0
- data/lib/decision_agent/data_enrichment/cache/memory_adapter.rb +86 -0
- data/lib/decision_agent/data_enrichment/cache_adapter.rb +49 -0
- data/lib/decision_agent/data_enrichment/circuit_breaker.rb +135 -0
- data/lib/decision_agent/data_enrichment/client.rb +220 -0
- data/lib/decision_agent/data_enrichment/config.rb +78 -0
- data/lib/decision_agent/data_enrichment/errors.rb +36 -0
- data/lib/decision_agent/decision.rb +102 -2
- data/lib/decision_agent/dmn/feel/evaluator.rb +28 -6
- data/lib/decision_agent/dsl/condition_evaluator.rb +982 -839
- data/lib/decision_agent/dsl/schema_validator.rb +51 -13
- data/lib/decision_agent/evaluators/dmn_evaluator.rb +106 -19
- data/lib/decision_agent/evaluators/json_rule_evaluator.rb +69 -9
- data/lib/decision_agent/explainability/condition_trace.rb +83 -0
- data/lib/decision_agent/explainability/explainability_result.rb +52 -0
- data/lib/decision_agent/explainability/rule_trace.rb +39 -0
- data/lib/decision_agent/explainability/trace_collector.rb +24 -0
- data/lib/decision_agent/monitoring/alert_manager.rb +5 -1
- data/lib/decision_agent/simulation/errors.rb +18 -0
- data/lib/decision_agent/simulation/impact_analyzer.rb +498 -0
- data/lib/decision_agent/simulation/monte_carlo_simulator.rb +635 -0
- data/lib/decision_agent/simulation/replay_engine.rb +486 -0
- data/lib/decision_agent/simulation/scenario_engine.rb +318 -0
- data/lib/decision_agent/simulation/scenario_library.rb +163 -0
- data/lib/decision_agent/simulation/shadow_test_engine.rb +287 -0
- data/lib/decision_agent/simulation/what_if_analyzer.rb +1002 -0
- data/lib/decision_agent/simulation.rb +17 -0
- data/lib/decision_agent/version.rb +1 -1
- data/lib/decision_agent/versioning/activerecord_adapter.rb +23 -8
- data/lib/decision_agent/web/public/app.js +119 -0
- data/lib/decision_agent/web/public/index.html +49 -0
- data/lib/decision_agent/web/public/simulation.html +130 -0
- data/lib/decision_agent/web/public/simulation_impact.html +478 -0
- data/lib/decision_agent/web/public/simulation_replay.html +551 -0
- data/lib/decision_agent/web/public/simulation_shadow.html +546 -0
- data/lib/decision_agent/web/public/simulation_whatif.html +532 -0
- data/lib/decision_agent/web/public/styles.css +65 -0
- data/lib/decision_agent/web/server.rb +594 -23
- data/lib/decision_agent.rb +60 -2
- metadata +53 -73
- data/spec/ab_testing/ab_test_assignment_spec.rb +0 -253
- data/spec/ab_testing/ab_test_manager_spec.rb +0 -612
- data/spec/ab_testing/ab_test_spec.rb +0 -270
- data/spec/ab_testing/ab_testing_agent_spec.rb +0 -655
- data/spec/ab_testing/storage/adapter_spec.rb +0 -64
- data/spec/ab_testing/storage/memory_adapter_spec.rb +0 -485
- data/spec/activerecord_thread_safety_spec.rb +0 -553
- data/spec/advanced_operators_spec.rb +0 -3150
- data/spec/agent_spec.rb +0 -289
- data/spec/api_contract_spec.rb +0 -430
- data/spec/audit_adapters_spec.rb +0 -92
- data/spec/auth/access_audit_logger_spec.rb +0 -394
- data/spec/auth/authenticator_spec.rb +0 -112
- data/spec/auth/password_reset_spec.rb +0 -294
- data/spec/auth/permission_checker_spec.rb +0 -207
- data/spec/auth/permission_spec.rb +0 -73
- data/spec/auth/rbac_adapter_spec.rb +0 -778
- data/spec/auth/rbac_config_spec.rb +0 -82
- data/spec/auth/role_spec.rb +0 -51
- data/spec/auth/session_manager_spec.rb +0 -172
- data/spec/auth/session_spec.rb +0 -112
- data/spec/auth/user_spec.rb +0 -130
- data/spec/comprehensive_edge_cases_spec.rb +0 -1777
- data/spec/context_spec.rb +0 -127
- data/spec/decision_agent_spec.rb +0 -96
- data/spec/decision_spec.rb +0 -423
- data/spec/dmn/decision_graph_spec.rb +0 -282
- data/spec/dmn/decision_tree_spec.rb +0 -203
- data/spec/dmn/feel/errors_spec.rb +0 -18
- data/spec/dmn/feel/functions_spec.rb +0 -400
- data/spec/dmn/feel/simple_parser_spec.rb +0 -274
- data/spec/dmn/feel/types_spec.rb +0 -176
- data/spec/dmn/feel_parser_spec.rb +0 -489
- data/spec/dmn/hit_policy_spec.rb +0 -202
- data/spec/dmn/integration_spec.rb +0 -226
- data/spec/dsl/condition_evaluator_spec.rb +0 -774
- data/spec/dsl_validation_spec.rb +0 -648
- data/spec/edge_cases_spec.rb +0 -353
- data/spec/evaluation_spec.rb +0 -364
- data/spec/evaluation_validator_spec.rb +0 -165
- data/spec/examples/feedback_aware_evaluator_spec.rb +0 -460
- data/spec/examples.txt +0 -1909
- data/spec/fixtures/dmn/complex_decision.dmn +0 -81
- data/spec/fixtures/dmn/invalid_structure.dmn +0 -31
- data/spec/fixtures/dmn/simple_decision.dmn +0 -40
- data/spec/issue_verification_spec.rb +0 -759
- data/spec/json_rule_evaluator_spec.rb +0 -587
- data/spec/monitoring/alert_manager_spec.rb +0 -378
- data/spec/monitoring/metrics_collector_spec.rb +0 -501
- data/spec/monitoring/monitored_agent_spec.rb +0 -225
- data/spec/monitoring/prometheus_exporter_spec.rb +0 -242
- data/spec/monitoring/storage/activerecord_adapter_spec.rb +0 -498
- data/spec/monitoring/storage/base_adapter_spec.rb +0 -61
- data/spec/monitoring/storage/memory_adapter_spec.rb +0 -247
- data/spec/performance_optimizations_spec.rb +0 -493
- data/spec/replay_edge_cases_spec.rb +0 -699
- data/spec/replay_spec.rb +0 -210
- data/spec/rfc8785_canonicalization_spec.rb +0 -215
- data/spec/scoring_spec.rb +0 -225
- data/spec/spec_helper.rb +0 -60
- data/spec/testing/batch_test_importer_spec.rb +0 -693
- data/spec/testing/batch_test_runner_spec.rb +0 -307
- data/spec/testing/test_coverage_analyzer_spec.rb +0 -292
- data/spec/testing/test_result_comparator_spec.rb +0 -392
- data/spec/testing/test_scenario_spec.rb +0 -113
- data/spec/thread_safety_spec.rb +0 -490
- data/spec/thread_safety_spec.rb.broken +0 -878
- data/spec/versioning/adapter_spec.rb +0 -156
- data/spec/versioning_spec.rb +0 -1030
- data/spec/web/middleware/auth_middleware_spec.rb +0 -133
- data/spec/web/middleware/permission_middleware_spec.rb +0 -247
- 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.
|
|
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
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
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
|
|
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
|
-
.
|
|
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">×</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
|
+
|