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.
Files changed (220) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +234 -14
  3. data/lib/decision_agent/ab_testing/ab_test.rb +5 -1
  4. data/lib/decision_agent/ab_testing/ab_test_assignment.rb +2 -0
  5. data/lib/decision_agent/ab_testing/ab_test_manager.rb +2 -0
  6. data/lib/decision_agent/ab_testing/ab_testing_agent.rb +2 -0
  7. data/lib/decision_agent/ab_testing/storage/activerecord_adapter.rb +2 -13
  8. data/lib/decision_agent/ab_testing/storage/adapter.rb +2 -0
  9. data/lib/decision_agent/ab_testing/storage/memory_adapter.rb +2 -0
  10. data/lib/decision_agent/agent.rb +78 -9
  11. data/lib/decision_agent/audit/adapter.rb +2 -0
  12. data/lib/decision_agent/audit/logger_adapter.rb +2 -0
  13. data/lib/decision_agent/audit/null_adapter.rb +2 -0
  14. data/lib/decision_agent/auth/access_audit_logger.rb +2 -0
  15. data/lib/decision_agent/auth/authenticator.rb +2 -0
  16. data/lib/decision_agent/auth/password_reset_manager.rb +2 -0
  17. data/lib/decision_agent/auth/password_reset_token.rb +2 -0
  18. data/lib/decision_agent/auth/permission.rb +2 -0
  19. data/lib/decision_agent/auth/permission_checker.rb +2 -0
  20. data/lib/decision_agent/auth/rbac_adapter.rb +2 -0
  21. data/lib/decision_agent/auth/rbac_config.rb +2 -0
  22. data/lib/decision_agent/auth/role.rb +2 -0
  23. data/lib/decision_agent/auth/session.rb +2 -0
  24. data/lib/decision_agent/auth/session_manager.rb +2 -0
  25. data/lib/decision_agent/auth/user.rb +2 -0
  26. data/lib/decision_agent/context.rb +14 -0
  27. data/lib/decision_agent/decision.rb +113 -4
  28. data/lib/decision_agent/dmn/adapter.rb +2 -0
  29. data/lib/decision_agent/dmn/cache.rb +2 -2
  30. data/lib/decision_agent/dmn/decision_graph.rb +7 -7
  31. data/lib/decision_agent/dmn/decision_tree.rb +16 -8
  32. data/lib/decision_agent/dmn/errors.rb +2 -0
  33. data/lib/decision_agent/dmn/exporter.rb +2 -0
  34. data/lib/decision_agent/dmn/feel/evaluator.rb +130 -114
  35. data/lib/decision_agent/dmn/feel/functions.rb +2 -0
  36. data/lib/decision_agent/dmn/feel/parser.rb +2 -0
  37. data/lib/decision_agent/dmn/feel/simple_parser.rb +98 -77
  38. data/lib/decision_agent/dmn/feel/transformer.rb +56 -102
  39. data/lib/decision_agent/dmn/feel/types.rb +2 -0
  40. data/lib/decision_agent/dmn/importer.rb +2 -0
  41. data/lib/decision_agent/dmn/model.rb +2 -4
  42. data/lib/decision_agent/dmn/parser.rb +2 -0
  43. data/lib/decision_agent/dmn/testing.rb +3 -2
  44. data/lib/decision_agent/dmn/validator.rb +5 -3
  45. data/lib/decision_agent/dmn/visualizer.rb +7 -6
  46. data/lib/decision_agent/dsl/condition_evaluator.rb +242 -1375
  47. data/lib/decision_agent/dsl/helpers/cache_helpers.rb +82 -0
  48. data/lib/decision_agent/dsl/helpers/comparison_helpers.rb +98 -0
  49. data/lib/decision_agent/dsl/helpers/date_helpers.rb +91 -0
  50. data/lib/decision_agent/dsl/helpers/geospatial_helpers.rb +85 -0
  51. data/lib/decision_agent/dsl/helpers/operator_evaluation_helpers.rb +160 -0
  52. data/lib/decision_agent/dsl/helpers/parameter_parsing_helpers.rb +206 -0
  53. data/lib/decision_agent/dsl/helpers/template_helpers.rb +39 -0
  54. data/lib/decision_agent/dsl/helpers/utility_helpers.rb +45 -0
  55. data/lib/decision_agent/dsl/operators/base.rb +70 -0
  56. data/lib/decision_agent/dsl/operators/basic_comparison_operators.rb +80 -0
  57. data/lib/decision_agent/dsl/operators/collection_operators.rb +60 -0
  58. data/lib/decision_agent/dsl/operators/date_arithmetic_operators.rb +206 -0
  59. data/lib/decision_agent/dsl/operators/date_time_operators.rb +47 -0
  60. data/lib/decision_agent/dsl/operators/duration_operators.rb +149 -0
  61. data/lib/decision_agent/dsl/operators/financial_operators.rb +237 -0
  62. data/lib/decision_agent/dsl/operators/geospatial_operators.rb +106 -0
  63. data/lib/decision_agent/dsl/operators/mathematical_operators.rb +234 -0
  64. data/lib/decision_agent/dsl/operators/moving_window_operators.rb +135 -0
  65. data/lib/decision_agent/dsl/operators/numeric_operators.rb +120 -0
  66. data/lib/decision_agent/dsl/operators/rate_operators.rb +65 -0
  67. data/lib/decision_agent/dsl/operators/statistical_aggregations.rb +187 -0
  68. data/lib/decision_agent/dsl/operators/string_aggregations.rb +84 -0
  69. data/lib/decision_agent/dsl/operators/string_operators.rb +72 -0
  70. data/lib/decision_agent/dsl/operators/time_component_operators.rb +72 -0
  71. data/lib/decision_agent/dsl/rule_parser.rb +2 -0
  72. data/lib/decision_agent/dsl/schema_validator.rb +37 -14
  73. data/lib/decision_agent/errors.rb +2 -0
  74. data/lib/decision_agent/evaluation.rb +14 -2
  75. data/lib/decision_agent/evaluators/base.rb +2 -0
  76. data/lib/decision_agent/evaluators/dmn_evaluator.rb +108 -19
  77. data/lib/decision_agent/evaluators/json_rule_evaluator.rb +56 -11
  78. data/lib/decision_agent/evaluators/static_evaluator.rb +2 -0
  79. data/lib/decision_agent/explainability/condition_trace.rb +85 -0
  80. data/lib/decision_agent/explainability/explainability_result.rb +50 -0
  81. data/lib/decision_agent/explainability/rule_trace.rb +41 -0
  82. data/lib/decision_agent/explainability/trace_collector.rb +26 -0
  83. data/lib/decision_agent/monitoring/alert_manager.rb +7 -16
  84. data/lib/decision_agent/monitoring/dashboard_server.rb +383 -250
  85. data/lib/decision_agent/monitoring/metrics_collector.rb +2 -0
  86. data/lib/decision_agent/monitoring/monitored_agent.rb +2 -0
  87. data/lib/decision_agent/monitoring/prometheus_exporter.rb +3 -1
  88. data/lib/decision_agent/replay/replay.rb +4 -1
  89. data/lib/decision_agent/scoring/base.rb +2 -0
  90. data/lib/decision_agent/scoring/consensus.rb +2 -0
  91. data/lib/decision_agent/scoring/max_weight.rb +2 -0
  92. data/lib/decision_agent/scoring/threshold.rb +2 -0
  93. data/lib/decision_agent/scoring/weighted_average.rb +2 -0
  94. data/lib/decision_agent/simulation/errors.rb +20 -0
  95. data/lib/decision_agent/simulation/impact_analyzer.rb +500 -0
  96. data/lib/decision_agent/simulation/monte_carlo_simulator.rb +638 -0
  97. data/lib/decision_agent/simulation/replay_engine.rb +488 -0
  98. data/lib/decision_agent/simulation/scenario_engine.rb +320 -0
  99. data/lib/decision_agent/simulation/scenario_library.rb +165 -0
  100. data/lib/decision_agent/simulation/shadow_test_engine.rb +274 -0
  101. data/lib/decision_agent/simulation/what_if_analyzer.rb +1008 -0
  102. data/lib/decision_agent/simulation.rb +19 -0
  103. data/lib/decision_agent/testing/batch_test_importer.rb +6 -2
  104. data/lib/decision_agent/testing/batch_test_runner.rb +5 -2
  105. data/lib/decision_agent/testing/test_coverage_analyzer.rb +2 -0
  106. data/lib/decision_agent/testing/test_result_comparator.rb +2 -0
  107. data/lib/decision_agent/testing/test_scenario.rb +2 -0
  108. data/lib/decision_agent/version.rb +3 -1
  109. data/lib/decision_agent/versioning/activerecord_adapter.rb +108 -43
  110. data/lib/decision_agent/versioning/adapter.rb +9 -0
  111. data/lib/decision_agent/versioning/file_storage_adapter.rb +19 -6
  112. data/lib/decision_agent/versioning/version_manager.rb +9 -0
  113. data/lib/decision_agent/web/dmn_editor/serialization.rb +74 -0
  114. data/lib/decision_agent/web/dmn_editor/xml_builder.rb +107 -0
  115. data/lib/decision_agent/web/dmn_editor.rb +8 -67
  116. data/lib/decision_agent/web/middleware/auth_middleware.rb +2 -0
  117. data/lib/decision_agent/web/middleware/permission_middleware.rb +3 -1
  118. data/lib/decision_agent/web/public/app.js +186 -26
  119. data/lib/decision_agent/web/public/batch_testing.html +80 -6
  120. data/lib/decision_agent/web/public/dmn-editor.html +2 -2
  121. data/lib/decision_agent/web/public/dmn-editor.js +74 -8
  122. data/lib/decision_agent/web/public/index.html +69 -3
  123. data/lib/decision_agent/web/public/login.html +1 -1
  124. data/lib/decision_agent/web/public/sample_batch.csv +11 -0
  125. data/lib/decision_agent/web/public/sample_impact.csv +11 -0
  126. data/lib/decision_agent/web/public/sample_replay.csv +11 -0
  127. data/lib/decision_agent/web/public/sample_rules.json +118 -0
  128. data/lib/decision_agent/web/public/sample_shadow.csv +11 -0
  129. data/lib/decision_agent/web/public/sample_whatif.csv +11 -0
  130. data/lib/decision_agent/web/public/simulation.html +146 -0
  131. data/lib/decision_agent/web/public/simulation_impact.html +495 -0
  132. data/lib/decision_agent/web/public/simulation_replay.html +547 -0
  133. data/lib/decision_agent/web/public/simulation_shadow.html +561 -0
  134. data/lib/decision_agent/web/public/simulation_whatif.html +549 -0
  135. data/lib/decision_agent/web/public/styles.css +65 -0
  136. data/lib/decision_agent/web/public/users.html +1 -1
  137. data/lib/decision_agent/web/rack_helpers.rb +106 -0
  138. data/lib/decision_agent/web/rack_request_helpers.rb +196 -0
  139. data/lib/decision_agent/web/server.rb +2126 -1374
  140. data/lib/decision_agent.rb +19 -1
  141. data/lib/generators/decision_agent/install/install_generator.rb +2 -0
  142. data/lib/generators/decision_agent/install/templates/ab_test_assignment_model.rb +2 -0
  143. data/lib/generators/decision_agent/install/templates/ab_test_model.rb +2 -0
  144. data/lib/generators/decision_agent/install/templates/ab_testing_migration.rb +2 -0
  145. data/lib/generators/decision_agent/install/templates/migration.rb +2 -0
  146. data/lib/generators/decision_agent/install/templates/rule.rb +2 -0
  147. data/lib/generators/decision_agent/install/templates/rule_version.rb +2 -0
  148. metadata +103 -89
  149. data/spec/ab_testing/ab_test_assignment_spec.rb +0 -253
  150. data/spec/ab_testing/ab_test_manager_spec.rb +0 -612
  151. data/spec/ab_testing/ab_test_spec.rb +0 -270
  152. data/spec/ab_testing/ab_testing_agent_spec.rb +0 -655
  153. data/spec/ab_testing/storage/adapter_spec.rb +0 -64
  154. data/spec/ab_testing/storage/memory_adapter_spec.rb +0 -485
  155. data/spec/activerecord_thread_safety_spec.rb +0 -553
  156. data/spec/advanced_operators_spec.rb +0 -3150
  157. data/spec/agent_spec.rb +0 -289
  158. data/spec/api_contract_spec.rb +0 -430
  159. data/spec/audit_adapters_spec.rb +0 -92
  160. data/spec/auth/access_audit_logger_spec.rb +0 -394
  161. data/spec/auth/authenticator_spec.rb +0 -112
  162. data/spec/auth/password_reset_spec.rb +0 -294
  163. data/spec/auth/permission_checker_spec.rb +0 -207
  164. data/spec/auth/permission_spec.rb +0 -73
  165. data/spec/auth/rbac_adapter_spec.rb +0 -778
  166. data/spec/auth/rbac_config_spec.rb +0 -82
  167. data/spec/auth/role_spec.rb +0 -51
  168. data/spec/auth/session_manager_spec.rb +0 -172
  169. data/spec/auth/session_spec.rb +0 -112
  170. data/spec/auth/user_spec.rb +0 -130
  171. data/spec/comprehensive_edge_cases_spec.rb +0 -1777
  172. data/spec/context_spec.rb +0 -127
  173. data/spec/decision_agent_spec.rb +0 -96
  174. data/spec/decision_spec.rb +0 -423
  175. data/spec/dmn/decision_graph_spec.rb +0 -282
  176. data/spec/dmn/decision_tree_spec.rb +0 -203
  177. data/spec/dmn/feel/errors_spec.rb +0 -18
  178. data/spec/dmn/feel/functions_spec.rb +0 -400
  179. data/spec/dmn/feel/simple_parser_spec.rb +0 -274
  180. data/spec/dmn/feel/types_spec.rb +0 -176
  181. data/spec/dmn/feel_parser_spec.rb +0 -489
  182. data/spec/dmn/hit_policy_spec.rb +0 -202
  183. data/spec/dmn/integration_spec.rb +0 -226
  184. data/spec/dsl/condition_evaluator_spec.rb +0 -774
  185. data/spec/dsl_validation_spec.rb +0 -648
  186. data/spec/edge_cases_spec.rb +0 -353
  187. data/spec/evaluation_spec.rb +0 -364
  188. data/spec/evaluation_validator_spec.rb +0 -165
  189. data/spec/examples/feedback_aware_evaluator_spec.rb +0 -460
  190. data/spec/examples.txt +0 -1909
  191. data/spec/fixtures/dmn/complex_decision.dmn +0 -81
  192. data/spec/fixtures/dmn/invalid_structure.dmn +0 -31
  193. data/spec/fixtures/dmn/simple_decision.dmn +0 -40
  194. data/spec/issue_verification_spec.rb +0 -759
  195. data/spec/json_rule_evaluator_spec.rb +0 -587
  196. data/spec/monitoring/alert_manager_spec.rb +0 -378
  197. data/spec/monitoring/metrics_collector_spec.rb +0 -501
  198. data/spec/monitoring/monitored_agent_spec.rb +0 -225
  199. data/spec/monitoring/prometheus_exporter_spec.rb +0 -242
  200. data/spec/monitoring/storage/activerecord_adapter_spec.rb +0 -498
  201. data/spec/monitoring/storage/base_adapter_spec.rb +0 -61
  202. data/spec/monitoring/storage/memory_adapter_spec.rb +0 -247
  203. data/spec/performance_optimizations_spec.rb +0 -493
  204. data/spec/replay_edge_cases_spec.rb +0 -699
  205. data/spec/replay_spec.rb +0 -210
  206. data/spec/rfc8785_canonicalization_spec.rb +0 -215
  207. data/spec/scoring_spec.rb +0 -225
  208. data/spec/spec_helper.rb +0 -60
  209. data/spec/testing/batch_test_importer_spec.rb +0 -693
  210. data/spec/testing/batch_test_runner_spec.rb +0 -307
  211. data/spec/testing/test_coverage_analyzer_spec.rb +0 -292
  212. data/spec/testing/test_result_comparator_spec.rb +0 -392
  213. data/spec/testing/test_scenario_spec.rb +0 -113
  214. data/spec/thread_safety_spec.rb +0 -490
  215. data/spec/thread_safety_spec.rb.broken +0 -878
  216. data/spec/versioning/adapter_spec.rb +0 -156
  217. data/spec/versioning_spec.rb +0 -1030
  218. data/spec/web/middleware/auth_middleware_spec.rb +0 -133
  219. data/spec/web/middleware/permission_middleware_spec.rb +0 -247
  220. 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: window.location.origin
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}/api/dmn${endpoint}`, options);
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) return;
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) return;
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) return;
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
- <button class="btn btn-secondary" id="loadExampleBtn">Load Example</button>
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">&times;</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
+