decision_agent 0.3.0 โ 1.1.0
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 +234 -14
- data/lib/decision_agent/ab_testing/ab_test.rb +5 -1
- data/lib/decision_agent/ab_testing/ab_test_assignment.rb +2 -0
- data/lib/decision_agent/ab_testing/ab_test_manager.rb +2 -0
- data/lib/decision_agent/ab_testing/ab_testing_agent.rb +2 -0
- data/lib/decision_agent/ab_testing/storage/activerecord_adapter.rb +2 -13
- data/lib/decision_agent/ab_testing/storage/adapter.rb +2 -0
- data/lib/decision_agent/ab_testing/storage/memory_adapter.rb +2 -0
- data/lib/decision_agent/agent.rb +78 -9
- data/lib/decision_agent/audit/adapter.rb +2 -0
- data/lib/decision_agent/audit/logger_adapter.rb +2 -0
- data/lib/decision_agent/audit/null_adapter.rb +2 -0
- data/lib/decision_agent/auth/access_audit_logger.rb +2 -0
- data/lib/decision_agent/auth/authenticator.rb +2 -0
- data/lib/decision_agent/auth/password_reset_manager.rb +2 -0
- data/lib/decision_agent/auth/password_reset_token.rb +2 -0
- data/lib/decision_agent/auth/permission.rb +2 -0
- data/lib/decision_agent/auth/permission_checker.rb +2 -0
- data/lib/decision_agent/auth/rbac_adapter.rb +2 -0
- data/lib/decision_agent/auth/rbac_config.rb +2 -0
- data/lib/decision_agent/auth/role.rb +2 -0
- data/lib/decision_agent/auth/session.rb +2 -0
- data/lib/decision_agent/auth/session_manager.rb +2 -0
- data/lib/decision_agent/auth/user.rb +2 -0
- data/lib/decision_agent/context.rb +14 -0
- data/lib/decision_agent/decision.rb +113 -4
- data/lib/decision_agent/dmn/adapter.rb +2 -0
- data/lib/decision_agent/dmn/cache.rb +2 -2
- data/lib/decision_agent/dmn/decision_graph.rb +7 -7
- data/lib/decision_agent/dmn/decision_tree.rb +16 -8
- data/lib/decision_agent/dmn/errors.rb +2 -0
- data/lib/decision_agent/dmn/exporter.rb +2 -0
- data/lib/decision_agent/dmn/feel/evaluator.rb +130 -114
- data/lib/decision_agent/dmn/feel/functions.rb +2 -0
- data/lib/decision_agent/dmn/feel/parser.rb +2 -0
- data/lib/decision_agent/dmn/feel/simple_parser.rb +98 -77
- data/lib/decision_agent/dmn/feel/transformer.rb +56 -102
- data/lib/decision_agent/dmn/feel/types.rb +2 -0
- data/lib/decision_agent/dmn/importer.rb +2 -0
- data/lib/decision_agent/dmn/model.rb +2 -4
- data/lib/decision_agent/dmn/parser.rb +2 -0
- data/lib/decision_agent/dmn/testing.rb +3 -2
- data/lib/decision_agent/dmn/validator.rb +5 -3
- data/lib/decision_agent/dmn/visualizer.rb +7 -6
- data/lib/decision_agent/dsl/condition_evaluator.rb +242 -1375
- data/lib/decision_agent/dsl/helpers/cache_helpers.rb +82 -0
- data/lib/decision_agent/dsl/helpers/comparison_helpers.rb +98 -0
- data/lib/decision_agent/dsl/helpers/date_helpers.rb +91 -0
- data/lib/decision_agent/dsl/helpers/geospatial_helpers.rb +85 -0
- data/lib/decision_agent/dsl/helpers/operator_evaluation_helpers.rb +160 -0
- data/lib/decision_agent/dsl/helpers/parameter_parsing_helpers.rb +206 -0
- data/lib/decision_agent/dsl/helpers/template_helpers.rb +39 -0
- data/lib/decision_agent/dsl/helpers/utility_helpers.rb +45 -0
- data/lib/decision_agent/dsl/operators/base.rb +70 -0
- data/lib/decision_agent/dsl/operators/basic_comparison_operators.rb +80 -0
- data/lib/decision_agent/dsl/operators/collection_operators.rb +60 -0
- data/lib/decision_agent/dsl/operators/date_arithmetic_operators.rb +206 -0
- data/lib/decision_agent/dsl/operators/date_time_operators.rb +47 -0
- data/lib/decision_agent/dsl/operators/duration_operators.rb +149 -0
- data/lib/decision_agent/dsl/operators/financial_operators.rb +237 -0
- data/lib/decision_agent/dsl/operators/geospatial_operators.rb +106 -0
- data/lib/decision_agent/dsl/operators/mathematical_operators.rb +234 -0
- data/lib/decision_agent/dsl/operators/moving_window_operators.rb +135 -0
- data/lib/decision_agent/dsl/operators/numeric_operators.rb +120 -0
- data/lib/decision_agent/dsl/operators/rate_operators.rb +65 -0
- data/lib/decision_agent/dsl/operators/statistical_aggregations.rb +187 -0
- data/lib/decision_agent/dsl/operators/string_aggregations.rb +84 -0
- data/lib/decision_agent/dsl/operators/string_operators.rb +72 -0
- data/lib/decision_agent/dsl/operators/time_component_operators.rb +72 -0
- data/lib/decision_agent/dsl/rule_parser.rb +2 -0
- data/lib/decision_agent/dsl/schema_validator.rb +37 -14
- data/lib/decision_agent/errors.rb +2 -0
- data/lib/decision_agent/evaluation.rb +14 -2
- data/lib/decision_agent/evaluators/base.rb +2 -0
- data/lib/decision_agent/evaluators/dmn_evaluator.rb +108 -19
- data/lib/decision_agent/evaluators/json_rule_evaluator.rb +56 -11
- data/lib/decision_agent/evaluators/static_evaluator.rb +2 -0
- data/lib/decision_agent/explainability/condition_trace.rb +85 -0
- data/lib/decision_agent/explainability/explainability_result.rb +50 -0
- data/lib/decision_agent/explainability/rule_trace.rb +41 -0
- data/lib/decision_agent/explainability/trace_collector.rb +26 -0
- data/lib/decision_agent/monitoring/alert_manager.rb +7 -16
- data/lib/decision_agent/monitoring/dashboard_server.rb +383 -250
- data/lib/decision_agent/monitoring/metrics_collector.rb +2 -0
- data/lib/decision_agent/monitoring/monitored_agent.rb +2 -0
- data/lib/decision_agent/monitoring/prometheus_exporter.rb +3 -1
- data/lib/decision_agent/replay/replay.rb +4 -1
- data/lib/decision_agent/scoring/base.rb +2 -0
- data/lib/decision_agent/scoring/consensus.rb +2 -0
- data/lib/decision_agent/scoring/max_weight.rb +2 -0
- data/lib/decision_agent/scoring/threshold.rb +2 -0
- data/lib/decision_agent/scoring/weighted_average.rb +2 -0
- data/lib/decision_agent/simulation/errors.rb +20 -0
- data/lib/decision_agent/simulation/impact_analyzer.rb +500 -0
- data/lib/decision_agent/simulation/monte_carlo_simulator.rb +638 -0
- data/lib/decision_agent/simulation/replay_engine.rb +488 -0
- data/lib/decision_agent/simulation/scenario_engine.rb +320 -0
- data/lib/decision_agent/simulation/scenario_library.rb +165 -0
- data/lib/decision_agent/simulation/shadow_test_engine.rb +274 -0
- data/lib/decision_agent/simulation/what_if_analyzer.rb +1008 -0
- data/lib/decision_agent/simulation.rb +19 -0
- data/lib/decision_agent/testing/batch_test_importer.rb +6 -2
- data/lib/decision_agent/testing/batch_test_runner.rb +5 -2
- data/lib/decision_agent/testing/test_coverage_analyzer.rb +2 -0
- data/lib/decision_agent/testing/test_result_comparator.rb +2 -0
- data/lib/decision_agent/testing/test_scenario.rb +2 -0
- data/lib/decision_agent/version.rb +3 -1
- data/lib/decision_agent/versioning/activerecord_adapter.rb +108 -43
- data/lib/decision_agent/versioning/adapter.rb +9 -0
- data/lib/decision_agent/versioning/file_storage_adapter.rb +19 -6
- data/lib/decision_agent/versioning/version_manager.rb +9 -0
- data/lib/decision_agent/web/dmn_editor/serialization.rb +74 -0
- data/lib/decision_agent/web/dmn_editor/xml_builder.rb +107 -0
- data/lib/decision_agent/web/dmn_editor.rb +8 -67
- data/lib/decision_agent/web/middleware/auth_middleware.rb +2 -0
- data/lib/decision_agent/web/middleware/permission_middleware.rb +3 -1
- data/lib/decision_agent/web/public/app.js +186 -26
- data/lib/decision_agent/web/public/batch_testing.html +80 -6
- data/lib/decision_agent/web/public/dmn-editor.html +2 -2
- data/lib/decision_agent/web/public/dmn-editor.js +74 -8
- data/lib/decision_agent/web/public/index.html +69 -3
- data/lib/decision_agent/web/public/login.html +1 -1
- data/lib/decision_agent/web/public/sample_batch.csv +11 -0
- data/lib/decision_agent/web/public/sample_impact.csv +11 -0
- data/lib/decision_agent/web/public/sample_replay.csv +11 -0
- data/lib/decision_agent/web/public/sample_rules.json +118 -0
- data/lib/decision_agent/web/public/sample_shadow.csv +11 -0
- data/lib/decision_agent/web/public/sample_whatif.csv +11 -0
- data/lib/decision_agent/web/public/simulation.html +146 -0
- data/lib/decision_agent/web/public/simulation_impact.html +495 -0
- data/lib/decision_agent/web/public/simulation_replay.html +547 -0
- data/lib/decision_agent/web/public/simulation_shadow.html +561 -0
- data/lib/decision_agent/web/public/simulation_whatif.html +549 -0
- data/lib/decision_agent/web/public/styles.css +65 -0
- data/lib/decision_agent/web/public/users.html +1 -1
- data/lib/decision_agent/web/rack_helpers.rb +106 -0
- data/lib/decision_agent/web/rack_request_helpers.rb +196 -0
- data/lib/decision_agent/web/server.rb +2126 -1374
- data/lib/decision_agent.rb +19 -1
- data/lib/generators/decision_agent/install/install_generator.rb +2 -0
- data/lib/generators/decision_agent/install/templates/ab_test_assignment_model.rb +2 -0
- data/lib/generators/decision_agent/install/templates/ab_test_model.rb +2 -0
- data/lib/generators/decision_agent/install/templates/ab_testing_migration.rb +2 -0
- data/lib/generators/decision_agent/install/templates/migration.rb +2 -0
- data/lib/generators/decision_agent/install/templates/rule.rb +2 -0
- data/lib/generators/decision_agent/install/templates/rule_version.rb +2 -0
- metadata +103 -89
- 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
|
@@ -1,11 +1,36 @@
|
|
|
1
1
|
// DMN Editor JavaScript
|
|
2
2
|
|
|
3
|
+
// Helper to get the base path for API calls
|
|
4
|
+
function getDmnBasePath() {
|
|
5
|
+
const baseTag = document.querySelector('base');
|
|
6
|
+
if (baseTag && baseTag.href) {
|
|
7
|
+
try {
|
|
8
|
+
const baseUrl = new URL(baseTag.href, window.location.href);
|
|
9
|
+
let path = baseUrl.pathname;
|
|
10
|
+
if (path && !path.endsWith('/')) path += '/';
|
|
11
|
+
return window.location.origin + path;
|
|
12
|
+
} catch (e) {
|
|
13
|
+
// fallback
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
const pathname = window.location.pathname;
|
|
17
|
+
const dirPath = pathname.substring(0, pathname.lastIndexOf('/') + 1);
|
|
18
|
+
return window.location.origin + (dirPath || '/');
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function getDmnAuthHeaders() {
|
|
22
|
+
const token = localStorage.getItem('auth_token');
|
|
23
|
+
const headers = { 'Content-Type': 'application/json' };
|
|
24
|
+
if (token) headers['Authorization'] = `Bearer ${token}`;
|
|
25
|
+
return headers;
|
|
26
|
+
}
|
|
27
|
+
|
|
3
28
|
// State
|
|
4
29
|
const state = {
|
|
5
30
|
currentModel: null,
|
|
6
31
|
currentDecision: null,
|
|
7
32
|
models: [],
|
|
8
|
-
baseUrl:
|
|
33
|
+
baseUrl: getDmnBasePath()
|
|
9
34
|
};
|
|
10
35
|
|
|
11
36
|
// Initialize
|
|
@@ -45,6 +70,10 @@ function initializeEventListeners() {
|
|
|
45
70
|
|
|
46
71
|
// Table controls
|
|
47
72
|
document.getElementById('add-input-btn').addEventListener('click', () => {
|
|
73
|
+
if (!state.currentModel || !state.currentDecision) {
|
|
74
|
+
showNotification('Please select or create a model and decision first', 'error');
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
48
77
|
document.getElementById('column-type').value = 'input';
|
|
49
78
|
document.getElementById('column-modal-title').textContent = 'Add Input Column';
|
|
50
79
|
document.getElementById('expression-group').style.display = 'block';
|
|
@@ -52,6 +81,10 @@ function initializeEventListeners() {
|
|
|
52
81
|
});
|
|
53
82
|
|
|
54
83
|
document.getElementById('add-output-btn').addEventListener('click', () => {
|
|
84
|
+
if (!state.currentModel || !state.currentDecision) {
|
|
85
|
+
showNotification('Please select or create a model and decision first', 'error');
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
55
88
|
document.getElementById('column-type').value = 'output';
|
|
56
89
|
document.getElementById('column-modal-title').textContent = 'Add Output Column';
|
|
57
90
|
document.getElementById('expression-group').style.display = 'none';
|
|
@@ -79,16 +112,14 @@ function initializeEventListeners() {
|
|
|
79
112
|
async function apiCall(endpoint, method = 'GET', data = null) {
|
|
80
113
|
const options = {
|
|
81
114
|
method,
|
|
82
|
-
headers:
|
|
83
|
-
'Content-Type': 'application/json'
|
|
84
|
-
}
|
|
115
|
+
headers: getDmnAuthHeaders()
|
|
85
116
|
};
|
|
86
117
|
|
|
87
118
|
if (data) {
|
|
88
119
|
options.body = JSON.stringify(data);
|
|
89
120
|
}
|
|
90
121
|
|
|
91
|
-
const response = await fetch(`${state.baseUrl}
|
|
122
|
+
const response = await fetch(`${state.baseUrl}api/dmn${endpoint}`, options);
|
|
92
123
|
|
|
93
124
|
if (!response.ok) {
|
|
94
125
|
const error = await response.json();
|
|
@@ -208,6 +239,11 @@ async function addDecision(e) {
|
|
|
208
239
|
}
|
|
209
240
|
|
|
210
241
|
async function loadDecision(decisionId) {
|
|
242
|
+
if (!state.currentModel || !state.currentModel.decisions) {
|
|
243
|
+
console.error('Cannot load decision: No model selected');
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
246
|
+
|
|
211
247
|
const decision = state.currentModel.decisions.find(d => d.id === decisionId);
|
|
212
248
|
if (!decision) return;
|
|
213
249
|
|
|
@@ -281,6 +317,12 @@ function renderDecisionTable(table) {
|
|
|
281
317
|
async function addColumn(e) {
|
|
282
318
|
e.preventDefault();
|
|
283
319
|
|
|
320
|
+
// Validate that model and decision are selected
|
|
321
|
+
if (!state.currentModel || !state.currentDecision) {
|
|
322
|
+
showNotification('Please select or create a model and decision first', 'error');
|
|
323
|
+
return;
|
|
324
|
+
}
|
|
325
|
+
|
|
284
326
|
const columnType = document.getElementById('column-type').value;
|
|
285
327
|
const id = document.getElementById('column-id-input').value;
|
|
286
328
|
const label = document.getElementById('column-label-input').value;
|
|
@@ -317,7 +359,10 @@ async function addColumn(e) {
|
|
|
317
359
|
}
|
|
318
360
|
|
|
319
361
|
async function addRule() {
|
|
320
|
-
if (!state.currentDecision || !state.currentDecision.decision_table)
|
|
362
|
+
if (!state.currentModel || !state.currentDecision || !state.currentDecision.decision_table) {
|
|
363
|
+
showNotification('Please select or create a model and decision first', 'error');
|
|
364
|
+
return;
|
|
365
|
+
}
|
|
321
366
|
|
|
322
367
|
const table = state.currentDecision.decision_table;
|
|
323
368
|
const ruleId = `rule_${Date.now()}`;
|
|
@@ -341,6 +386,11 @@ async function addRule() {
|
|
|
341
386
|
}
|
|
342
387
|
|
|
343
388
|
async function updateRuleEntry(ruleId, type, index, value) {
|
|
389
|
+
if (!state.currentModel || !state.currentDecision || !state.currentDecision.decision_table) {
|
|
390
|
+
showNotification('Please select or create a model and decision first', 'error');
|
|
391
|
+
return;
|
|
392
|
+
}
|
|
393
|
+
|
|
344
394
|
try {
|
|
345
395
|
const rule = state.currentDecision.decision_table.rules.find(r => r.id === ruleId);
|
|
346
396
|
if (!rule) return;
|
|
@@ -361,6 +411,11 @@ async function updateRuleEntry(ruleId, type, index, value) {
|
|
|
361
411
|
}
|
|
362
412
|
|
|
363
413
|
async function deleteRule(ruleId) {
|
|
414
|
+
if (!state.currentModel || !state.currentDecision) {
|
|
415
|
+
showNotification('Please select or create a model and decision first', 'error');
|
|
416
|
+
return;
|
|
417
|
+
}
|
|
418
|
+
|
|
364
419
|
if (!confirm('Are you sure you want to delete this rule?')) return;
|
|
365
420
|
|
|
366
421
|
try {
|
|
@@ -376,7 +431,10 @@ async function deleteRule(ruleId) {
|
|
|
376
431
|
}
|
|
377
432
|
|
|
378
433
|
async function updateHitPolicy(e) {
|
|
379
|
-
if (!state.currentDecision || !state.currentDecision.decision_table)
|
|
434
|
+
if (!state.currentModel || !state.currentDecision || !state.currentDecision.decision_table) {
|
|
435
|
+
showNotification('Please select or create a model and decision first', 'error');
|
|
436
|
+
return;
|
|
437
|
+
}
|
|
380
438
|
|
|
381
439
|
try {
|
|
382
440
|
await apiCall(`/models/${state.currentModel.id}/decisions/${state.currentDecision.id}`, 'PUT', {
|
|
@@ -473,7 +531,10 @@ async function visualizeGraph() {
|
|
|
473
531
|
}
|
|
474
532
|
|
|
475
533
|
async function visualizeTree() {
|
|
476
|
-
if (!state.currentDecision)
|
|
534
|
+
if (!state.currentModel || !state.currentDecision) {
|
|
535
|
+
showNotification('Please select or create a model and decision first', 'error');
|
|
536
|
+
return;
|
|
537
|
+
}
|
|
477
538
|
|
|
478
539
|
try {
|
|
479
540
|
const svg = await apiCall(`/models/${state.currentModel.id}/decisions/${state.currentDecision.id}/visualize/tree`);
|
|
@@ -490,6 +551,11 @@ function copyXml() {
|
|
|
490
551
|
}
|
|
491
552
|
|
|
492
553
|
function downloadXml() {
|
|
554
|
+
if (!state.currentModel) {
|
|
555
|
+
showNotification('No model selected', 'warning');
|
|
556
|
+
return;
|
|
557
|
+
}
|
|
558
|
+
|
|
493
559
|
const xmlContent = document.getElementById('xml-content').textContent;
|
|
494
560
|
const blob = new Blob([xmlContent], { type: 'text/xml' });
|
|
495
561
|
const url = URL.createObjectURL(blob);
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
<meta charset="UTF-8">
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
6
|
<title>DecisionAgent Rule Builder</title>
|
|
7
|
-
<link rel="stylesheet" href="styles.css">
|
|
7
|
+
<link rel="stylesheet" href="/styles.css">
|
|
8
8
|
</head>
|
|
9
9
|
<body>
|
|
10
10
|
<div class="container">
|
|
@@ -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
|
|
|
@@ -21,7 +23,10 @@
|
|
|
21
23
|
<div class="panel builder-panel">
|
|
22
24
|
<div class="panel-header">
|
|
23
25
|
<h2>Rule Configuration</h2>
|
|
24
|
-
<
|
|
26
|
+
<div>
|
|
27
|
+
<button class="btn btn-secondary" id="loadExampleBtn">Load Example</button>
|
|
28
|
+
<a href="/sample_rules.json" download class="btn btn-secondary" style="margin-left: 10px; text-decoration: none;">๐ฅ Sample JSON</a>
|
|
29
|
+
</div>
|
|
25
30
|
</div>
|
|
26
31
|
|
|
27
32
|
<!-- Ruleset Metadata -->
|
|
@@ -51,6 +56,7 @@
|
|
|
51
56
|
<!-- Action Buttons -->
|
|
52
57
|
<div class="actions">
|
|
53
58
|
<button class="btn btn-success" id="validateBtn">โ Validate Rules</button>
|
|
59
|
+
<button class="btn btn-info" id="testRuleBtn">๐งช Test Rule</button>
|
|
54
60
|
<button class="btn btn-primary" id="saveVersionBtn">๐พ Save Version</button>
|
|
55
61
|
<button class="btn btn-secondary" id="clearBtn">Clear All</button>
|
|
56
62
|
</div>
|
|
@@ -188,14 +194,28 @@
|
|
|
188
194
|
<option value="sin">sin (trigonometric)</option>
|
|
189
195
|
<option value="cos">cos (trigonometric)</option>
|
|
190
196
|
<option value="tan">tan (trigonometric)</option>
|
|
197
|
+
<option value="asin">asin (arc sine)</option>
|
|
198
|
+
<option value="acos">acos (arc cosine)</option>
|
|
199
|
+
<option value="atan">atan (arc tangent)</option>
|
|
200
|
+
<option value="atan2">atan2 (arc tangent of y/x)</option>
|
|
201
|
+
<option value="sinh">sinh (hyperbolic sine)</option>
|
|
202
|
+
<option value="cosh">cosh (hyperbolic cosine)</option>
|
|
203
|
+
<option value="tanh">tanh (hyperbolic tangent)</option>
|
|
191
204
|
<option value="sqrt">sqrt (square root)</option>
|
|
205
|
+
<option value="cbrt">cbrt (cube root)</option>
|
|
192
206
|
<option value="power">power (exponentiation)</option>
|
|
193
207
|
<option value="exp">exp (exponential)</option>
|
|
194
208
|
<option value="log">log (natural logarithm)</option>
|
|
209
|
+
<option value="log10">log10 (base 10 logarithm)</option>
|
|
210
|
+
<option value="log2">log2 (base 2 logarithm)</option>
|
|
195
211
|
<option value="round">round</option>
|
|
196
212
|
<option value="floor">floor</option>
|
|
197
213
|
<option value="ceil">ceil</option>
|
|
214
|
+
<option value="truncate">truncate</option>
|
|
198
215
|
<option value="abs">abs (absolute value)</option>
|
|
216
|
+
<option value="factorial">factorial</option>
|
|
217
|
+
<option value="gcd">gcd (greatest common divisor)</option>
|
|
218
|
+
<option value="lcm">lcm (least common multiple)</option>
|
|
199
219
|
<option value="min">min (array minimum)</option>
|
|
200
220
|
<option value="max">max (array maximum)</option>
|
|
201
221
|
</optgroup>
|
|
@@ -333,12 +353,58 @@
|
|
|
333
353
|
</div>
|
|
334
354
|
</div>
|
|
335
355
|
</div>
|
|
356
|
+
|
|
357
|
+
<!-- Test Rule Modal -->
|
|
358
|
+
<div id="testRuleModal" class="modal hidden">
|
|
359
|
+
<div class="modal-content modal-large">
|
|
360
|
+
<div class="modal-header">
|
|
361
|
+
<h2>๐งช Test Rule</h2>
|
|
362
|
+
<button class="close-btn" id="closeTestRuleBtn">×</button>
|
|
363
|
+
</div>
|
|
364
|
+
<div class="modal-body">
|
|
365
|
+
<div class="form-group">
|
|
366
|
+
<label for="testContext">Test Context (JSON):</label>
|
|
367
|
+
<textarea id="testContext" class="input" rows="8" placeholder='{"field1": "value1", "field2": 123}'></textarea>
|
|
368
|
+
<small class="form-hint">Enter context data as JSON to test your rules</small>
|
|
369
|
+
</div>
|
|
370
|
+
<div class="actions" style="margin-top: 1rem;">
|
|
371
|
+
<button class="btn btn-primary" id="runTestBtn">Run Test</button>
|
|
372
|
+
</div>
|
|
373
|
+
<div id="testResults" class="test-results hidden" style="margin-top: 2rem;">
|
|
374
|
+
<h3>Test Results</h3>
|
|
375
|
+
<div id="testDecision" class="test-result-item">
|
|
376
|
+
<strong>Decision:</strong> <span id="testDecisionValue">-</span>
|
|
377
|
+
</div>
|
|
378
|
+
<div id="testConfidence" class="test-result-item">
|
|
379
|
+
<strong>Confidence:</strong> <span id="testConfidenceValue">-</span>
|
|
380
|
+
</div>
|
|
381
|
+
<div id="testReason" class="test-result-item">
|
|
382
|
+
<strong>Reason:</strong> <span id="testReasonValue">-</span>
|
|
383
|
+
</div>
|
|
384
|
+
<div id="testExplainability" class="test-explainability" style="margin-top: 1.5rem;">
|
|
385
|
+
<h4>Explainability</h4>
|
|
386
|
+
<div id="testBecause" class="test-because">
|
|
387
|
+
<strong>Because (conditions that led to decision):</strong>
|
|
388
|
+
<ul id="testBecauseList"></ul>
|
|
389
|
+
</div>
|
|
390
|
+
<div id="testFailedConditions" class="test-failed" style="margin-top: 1rem;">
|
|
391
|
+
<strong>Failed Conditions:</strong>
|
|
392
|
+
<ul id="testFailedList"></ul>
|
|
393
|
+
</div>
|
|
394
|
+
</div>
|
|
395
|
+
</div>
|
|
396
|
+
</div>
|
|
397
|
+
<div class="modal-footer">
|
|
398
|
+
<button class="btn btn-secondary" id="closeTestRuleModalBtn">Close</button>
|
|
399
|
+
</div>
|
|
400
|
+
</div>
|
|
401
|
+
</div>
|
|
336
402
|
</div>
|
|
337
403
|
|
|
338
404
|
<footer class="footer">
|
|
339
405
|
<p>DecisionAgent Rule Builder | <a href="https://github.com/samaswin/decision_agent" target="_blank">Documentation</a></p>
|
|
340
406
|
</footer>
|
|
341
407
|
|
|
342
|
-
<script src="app.js"></script>
|
|
408
|
+
<script src="/app.js"></script>
|
|
343
409
|
</body>
|
|
344
410
|
</html>
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
<meta charset="UTF-8">
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
6
|
<title>Login - DecisionAgent</title>
|
|
7
|
-
<link rel="stylesheet" href="styles.css">
|
|
7
|
+
<link rel="stylesheet" href="/styles.css">
|
|
8
8
|
<style>
|
|
9
9
|
.login-container {
|
|
10
10
|
max-width: 400px;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
id,user_id,amount,transaction_type,account_age_days,risk_score,country,expected_decision,expected_confidence
|
|
2
|
+
test_001,user_123,1500,purchase,365,0.2,US,approve,0.95
|
|
3
|
+
test_002,user_456,5000,withdrawal,730,0.3,US,approve,0.85
|
|
4
|
+
test_003,user_789,15000,transfer,90,0.7,BR,manual_review,0.75
|
|
5
|
+
test_004,user_321,50000,withdrawal,45,0.85,NG,reject,0.90
|
|
6
|
+
test_005,user_654,2500,purchase,1095,0.15,CA,approve,0.95
|
|
7
|
+
test_006,user_987,8000,transfer,180,0.55,GB,manual_review,0.80
|
|
8
|
+
test_007,user_111,500,purchase,1825,0.1,US,approve,0.98
|
|
9
|
+
test_008,user_222,75000,withdrawal,30,0.95,RU,reject,0.95
|
|
10
|
+
test_009,user_333,3000,purchase,548,0.25,DE,approve,0.90
|
|
11
|
+
test_010,user_444,12000,transfer,274,0.45,FR,approve,0.85
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
id,user_id,amount,transaction_type,account_age_days,risk_score,country,baseline_decision,new_decision,impact_category
|
|
2
|
+
imp_001,user_123,1500,purchase,365,0.2,US,approve,approve,no_change
|
|
3
|
+
imp_002,user_456,5000,withdrawal,730,0.3,US,approve,approve,no_change
|
|
4
|
+
imp_003,user_789,15000,transfer,90,0.7,BR,manual_review,reject,higher_security
|
|
5
|
+
imp_004,user_321,50000,withdrawal,45,0.85,NG,reject,reject,no_change
|
|
6
|
+
imp_005,user_654,2500,purchase,1095,0.15,CA,approve,approve,no_change
|
|
7
|
+
imp_006,user_987,8000,transfer,180,0.55,GB,approve,manual_review,higher_security
|
|
8
|
+
imp_007,user_111,500,purchase,1825,0.1,US,approve,approve,no_change
|
|
9
|
+
imp_008,user_222,75000,withdrawal,30,0.95,RU,reject,reject,no_change
|
|
10
|
+
imp_009,user_333,3000,purchase,548,0.25,DE,approve,approve,no_change
|
|
11
|
+
imp_010,user_444,12000,transfer,274,0.45,FR,manual_review,approve,lower_friction
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
id,timestamp,user_id,amount,transaction_type,account_age_days,risk_score,country,decision_v1,decision_v2
|
|
2
|
+
hist_001,2024-01-15T10:30:00Z,user_123,1500,purchase,365,0.2,US,approve,approve
|
|
3
|
+
hist_002,2024-01-15T11:45:00Z,user_456,5000,withdrawal,730,0.3,US,approve,approve
|
|
4
|
+
hist_003,2024-01-15T12:20:00Z,user_789,15000,transfer,90,0.7,BR,manual_review,reject
|
|
5
|
+
hist_004,2024-01-15T13:10:00Z,user_321,50000,withdrawal,45,0.85,NG,reject,reject
|
|
6
|
+
hist_005,2024-01-15T14:05:00Z,user_654,2500,purchase,1095,0.15,CA,approve,approve
|
|
7
|
+
hist_006,2024-01-15T15:30:00Z,user_987,8000,transfer,180,0.55,GB,manual_review,manual_review
|
|
8
|
+
hist_007,2024-01-15T16:15:00Z,user_111,500,purchase,1825,0.1,US,approve,approve
|
|
9
|
+
hist_008,2024-01-15T17:45:00Z,user_222,75000,withdrawal,30,0.95,RU,reject,reject
|
|
10
|
+
hist_009,2024-01-15T18:20:00Z,user_333,3000,purchase,548,0.25,DE,approve,approve
|
|
11
|
+
hist_010,2024-01-15T19:00:00Z,user_444,12000,transfer,274,0.45,FR,approve,manual_review
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": "1.0",
|
|
3
|
+
"ruleset": "transaction_approval",
|
|
4
|
+
"description": "Sample ruleset for transaction approval with fraud detection",
|
|
5
|
+
"rules": [
|
|
6
|
+
{
|
|
7
|
+
"id": "rule_001",
|
|
8
|
+
"name": "High Risk Country Block",
|
|
9
|
+
"if": {
|
|
10
|
+
"all": [
|
|
11
|
+
{
|
|
12
|
+
"field": "country",
|
|
13
|
+
"op": "in",
|
|
14
|
+
"value": ["NG", "RU", "CN"]
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
"field": "risk_score",
|
|
18
|
+
"op": "gte",
|
|
19
|
+
"value": 0.7
|
|
20
|
+
}
|
|
21
|
+
]
|
|
22
|
+
},
|
|
23
|
+
"then": {
|
|
24
|
+
"decision": "reject",
|
|
25
|
+
"weight": 0.95,
|
|
26
|
+
"reason": "High risk country with elevated risk score"
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
"id": "rule_002",
|
|
31
|
+
"name": "Large Amount Manual Review",
|
|
32
|
+
"if": {
|
|
33
|
+
"field": "amount",
|
|
34
|
+
"op": "gte",
|
|
35
|
+
"value": 10000
|
|
36
|
+
},
|
|
37
|
+
"then": {
|
|
38
|
+
"decision": "manual_review",
|
|
39
|
+
"weight": 0.85,
|
|
40
|
+
"reason": "Large transaction amount requires manual review"
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
"id": "rule_003",
|
|
45
|
+
"name": "New Account Large Transaction",
|
|
46
|
+
"if": {
|
|
47
|
+
"all": [
|
|
48
|
+
{
|
|
49
|
+
"field": "account_age_days",
|
|
50
|
+
"op": "lt",
|
|
51
|
+
"value": 90
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
"field": "amount",
|
|
55
|
+
"op": "gte",
|
|
56
|
+
"value": 5000
|
|
57
|
+
}
|
|
58
|
+
]
|
|
59
|
+
},
|
|
60
|
+
"then": {
|
|
61
|
+
"decision": "manual_review",
|
|
62
|
+
"weight": 0.80,
|
|
63
|
+
"reason": "New account with large transaction"
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
"id": "rule_004",
|
|
68
|
+
"name": "Low Risk Auto Approve",
|
|
69
|
+
"if": {
|
|
70
|
+
"all": [
|
|
71
|
+
{
|
|
72
|
+
"field": "risk_score",
|
|
73
|
+
"op": "lte",
|
|
74
|
+
"value": 0.3
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
"field": "account_age_days",
|
|
78
|
+
"op": "gte",
|
|
79
|
+
"value": 365
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
"field": "amount",
|
|
83
|
+
"op": "lte",
|
|
84
|
+
"value": 5000
|
|
85
|
+
}
|
|
86
|
+
]
|
|
87
|
+
},
|
|
88
|
+
"then": {
|
|
89
|
+
"decision": "approve",
|
|
90
|
+
"weight": 0.95,
|
|
91
|
+
"reason": "Low risk profile, established account, reasonable amount"
|
|
92
|
+
}
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
"id": "rule_005",
|
|
96
|
+
"name": "Medium Risk Review",
|
|
97
|
+
"if": {
|
|
98
|
+
"all": [
|
|
99
|
+
{
|
|
100
|
+
"field": "risk_score",
|
|
101
|
+
"op": "gt",
|
|
102
|
+
"value": 0.5
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
"field": "risk_score",
|
|
106
|
+
"op": "lt",
|
|
107
|
+
"value": 0.7
|
|
108
|
+
}
|
|
109
|
+
]
|
|
110
|
+
},
|
|
111
|
+
"then": {
|
|
112
|
+
"decision": "manual_review",
|
|
113
|
+
"weight": 0.75,
|
|
114
|
+
"reason": "Medium risk score requires review"
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
]
|
|
118
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
id,timestamp,user_id,amount,transaction_type,account_age_days,risk_score,country,production_decision
|
|
2
|
+
shadow_001,2024-01-20T10:00:00Z,user_123,1200,purchase,400,0.18,US,approve
|
|
3
|
+
shadow_002,2024-01-20T10:15:00Z,user_456,4500,withdrawal,800,0.28,GB,approve
|
|
4
|
+
shadow_003,2024-01-20T10:30:00Z,user_789,18000,transfer,120,0.65,BR,manual_review
|
|
5
|
+
shadow_004,2024-01-20T10:45:00Z,user_321,55000,withdrawal,50,0.88,NG,reject
|
|
6
|
+
shadow_005,2024-01-20T11:00:00Z,user_654,2800,purchase,1200,0.12,CA,approve
|
|
7
|
+
shadow_006,2024-01-20T11:15:00Z,user_987,9500,transfer,200,0.58,FR,manual_review
|
|
8
|
+
shadow_007,2024-01-20T11:30:00Z,user_111,600,purchase,2000,0.08,US,approve
|
|
9
|
+
shadow_008,2024-01-20T11:45:00Z,user_222,80000,withdrawal,25,0.98,RU,reject
|
|
10
|
+
shadow_009,2024-01-20T12:00:00Z,user_333,3500,purchase,600,0.22,DE,approve
|
|
11
|
+
shadow_010,2024-01-20T12:15:00Z,user_444,11000,transfer,300,0.48,GB,approve
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
scenario_name,user_id,amount,transaction_type,account_age_days,risk_score,country
|
|
2
|
+
low_risk_small,user_123,1000,purchase,730,0.1,US
|
|
3
|
+
low_risk_large,user_123,10000,purchase,730,0.1,US
|
|
4
|
+
medium_risk_small,user_456,1000,purchase,365,0.6,GB
|
|
5
|
+
medium_risk_large,user_456,10000,purchase,365,0.6,GB
|
|
6
|
+
high_risk_small,user_789,1000,purchase,90,0.9,NG
|
|
7
|
+
high_risk_large,user_789,10000,purchase,90,0.9,NG
|
|
8
|
+
new_account_small,user_321,500,purchase,30,0.3,US
|
|
9
|
+
new_account_large,user_321,5000,purchase,30,0.3,US
|
|
10
|
+
established_account,user_654,7500,withdrawal,1825,0.2,CA
|
|
11
|
+
risky_country,user_987,3000,transfer,365,0.4,RU
|
|
@@ -0,0 +1,146 @@
|
|
|
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
|
+
.dashboard-header .header-links {
|
|
57
|
+
display: flex;
|
|
58
|
+
gap: 1rem;
|
|
59
|
+
align-items: center;
|
|
60
|
+
margin-top: 1.5rem;
|
|
61
|
+
padding-top: 1rem;
|
|
62
|
+
border-top: 1px solid rgba(255, 255, 255, 0.1);
|
|
63
|
+
position: static;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
.dashboard-header .header-links a {
|
|
67
|
+
padding: 0.5rem 1rem;
|
|
68
|
+
border-radius: 6px;
|
|
69
|
+
text-decoration: none;
|
|
70
|
+
color: white;
|
|
71
|
+
background: rgba(255, 255, 255, 0.1);
|
|
72
|
+
transition: all 0.2s;
|
|
73
|
+
font-size: 0.9rem;
|
|
74
|
+
border: 1px solid rgba(255, 255, 255, 0.2);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
.dashboard-header .header-links a:hover {
|
|
78
|
+
background: rgba(255, 255, 255, 0.2);
|
|
79
|
+
transform: translateY(-1px);
|
|
80
|
+
}
|
|
81
|
+
</style>
|
|
82
|
+
</head>
|
|
83
|
+
<body>
|
|
84
|
+
<div class="simulation-dashboard">
|
|
85
|
+
<header class="dashboard-header">
|
|
86
|
+
<h1>๐งช DecisionAgent Simulation Dashboard</h1>
|
|
87
|
+
<p class="subtitle">Test rule changes, predict impact, and validate decisions before deployment</p>
|
|
88
|
+
<div class="header-links">
|
|
89
|
+
<a href="/">๐ Rule Builder</a>
|
|
90
|
+
<a href="/testing/batch">๐ Batch Testing</a>
|
|
91
|
+
<a href="/dmn/editor">๐ DMN Editor</a>
|
|
92
|
+
</div>
|
|
93
|
+
</header>
|
|
94
|
+
|
|
95
|
+
<div class="feature-grid">
|
|
96
|
+
<a href="/simulation/replay" class="feature-card">
|
|
97
|
+
<div class="feature-icon">๐</div>
|
|
98
|
+
<div class="feature-title">Historical Replay / Backtesting</div>
|
|
99
|
+
<div class="feature-description">
|
|
100
|
+
Replay historical decisions with different rule versions to see how outcomes would change.
|
|
101
|
+
Compare baseline vs. proposed versions and analyze decision changes.
|
|
102
|
+
</div>
|
|
103
|
+
</a>
|
|
104
|
+
|
|
105
|
+
<a href="/simulation/whatif" class="feature-card">
|
|
106
|
+
<div class="feature-icon">โ</div>
|
|
107
|
+
<div class="feature-title">What-If Analysis</div>
|
|
108
|
+
<div class="feature-description">
|
|
109
|
+
Simulate different scenarios and analyze how decisions change based on input variations.
|
|
110
|
+
Perform sensitivity analysis to identify which inputs matter most.
|
|
111
|
+
</div>
|
|
112
|
+
</a>
|
|
113
|
+
|
|
114
|
+
<a href="/simulation/impact" class="feature-card">
|
|
115
|
+
<div class="feature-icon">๐</div>
|
|
116
|
+
<div class="feature-title">Impact Analysis</div>
|
|
117
|
+
<div class="feature-description">
|
|
118
|
+
Quantify the impact of rule changes before deploying to production.
|
|
119
|
+
Get risk scores, decision distribution changes, and confidence shifts.
|
|
120
|
+
</div>
|
|
121
|
+
</a>
|
|
122
|
+
|
|
123
|
+
<a href="/simulation/shadow" class="feature-card">
|
|
124
|
+
<div class="feature-icon">๐ป</div>
|
|
125
|
+
<div class="feature-title">Shadow Testing</div>
|
|
126
|
+
<div class="feature-description">
|
|
127
|
+
Compare new rules against production without affecting actual outcomes.
|
|
128
|
+
Test on production traffic with zero impact on real decisions.
|
|
129
|
+
</div>
|
|
130
|
+
</a>
|
|
131
|
+
</div>
|
|
132
|
+
|
|
133
|
+
<div style="margin-top: 40px; padding: 20px; background: var(--panel-bg); border-radius: 10px;">
|
|
134
|
+
<h2>Quick Start</h2>
|
|
135
|
+
<p>Choose a simulation type above to get started:</p>
|
|
136
|
+
<ul style="line-height: 2;">
|
|
137
|
+
<li><strong>Historical Replay:</strong> Upload historical data (CSV/JSON) and replay with different rule versions</li>
|
|
138
|
+
<li><strong>What-If Analysis:</strong> Define scenarios and see how decisions change</li>
|
|
139
|
+
<li><strong>Impact Analysis:</strong> Compare two rule versions to assess change impact</li>
|
|
140
|
+
<li><strong>Shadow Testing:</strong> Test new rules alongside production without affecting outcomes</li>
|
|
141
|
+
</ul>
|
|
142
|
+
</div>
|
|
143
|
+
</div>
|
|
144
|
+
</body>
|
|
145
|
+
</html>
|
|
146
|
+
|