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,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative "decision_agent/version"
2
4
  require_relative "decision_agent/errors"
3
5
  require_relative "decision_agent/context"
@@ -62,9 +64,18 @@ require_relative "decision_agent/auth/rbac_config"
62
64
  require_relative "decision_agent/auth/permission_checker"
63
65
  require_relative "decision_agent/auth/access_audit_logger"
64
66
 
67
+ require_relative "decision_agent/simulation"
68
+
69
+ require_relative "decision_agent/explainability/condition_trace"
70
+ require_relative "decision_agent/explainability/rule_trace"
71
+ require_relative "decision_agent/explainability/trace_collector"
72
+ require_relative "decision_agent/explainability/explainability_result"
73
+
65
74
  module DecisionAgent
66
75
  # Global RBAC configuration
67
76
  @rbac_config = Auth::RbacConfig.new
77
+ @permission_checker = nil
78
+ @permission_checker_mutex = Mutex.new
68
79
 
69
80
  class << self
70
81
  attr_reader :rbac_config
@@ -85,12 +96,19 @@ module DecisionAgent
85
96
  elsif adapter_type
86
97
  @rbac_config.use(adapter_type, **options)
87
98
  end
99
+ # Initialize permission checker at configuration time (thread-safe write-once pattern)
100
+ @permission_checker = Auth::PermissionChecker.new(adapter: @rbac_config.adapter)
88
101
  @rbac_config
89
102
  end
90
103
 
91
104
  # Get the configured permission checker
105
+ # Thread-safe: uses double-checked locking for lazy initialization fallback
92
106
  def permission_checker
93
- @permission_checker ||= Auth::PermissionChecker.new(adapter: @rbac_config.adapter)
107
+ return @permission_checker if @permission_checker
108
+
109
+ @permission_checker_mutex.synchronize do
110
+ @permission_checker ||= Auth::PermissionChecker.new(adapter: @rbac_config.adapter)
111
+ end
94
112
  end
95
113
 
96
114
  # Set a custom permission checker
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "rails/generators"
2
4
  require "rails/generators/migration"
3
5
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # A/B Test Assignment model for decision_agent gem
2
4
  # Tracks individual variant assignments and their results
3
5
  class ABTestAssignmentModel < ActiveRecord::Base
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # A/B Test model for decision_agent gem
2
4
  # Stores A/B test configurations
3
5
  class ABTestModel < ActiveRecord::Base
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class CreateDecisionAgentABTestingTables < ActiveRecord::Migration[7.0]
2
4
  def change
3
5
  # A/B Tests table
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class CreateDecisionAgentTables < ActiveRecord::Migration[7.0]
2
4
  def change
3
5
  # Rules table
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Rule < ApplicationRecord
2
4
  has_many :rule_versions, primary_key: :rule_id, foreign_key: :rule_id, dependent: :destroy
3
5
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class RuleVersion < ApplicationRecord
2
4
  belongs_to :rule, primary_key: :rule_id, foreign_key: :rule_id, optional: true
3
5
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: decision_agent
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sam Aswin
@@ -23,6 +23,20 @@ dependencies:
23
23
  - - "~>"
24
24
  - !ruby/object:Gem::Version
25
25
  version: '3.1'
26
+ - !ruby/object:Gem::Dependency
27
+ name: csv
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - "~>"
31
+ - !ruby/object:Gem::Version
32
+ version: '3.3'
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '3.3'
26
40
  - !ruby/object:Gem::Dependency
27
41
  name: json-canonicalization
28
42
  requirement: !ruby/object:Gem::Requirement
@@ -41,16 +55,22 @@ dependencies:
41
55
  name: nokogiri
42
56
  requirement: !ruby/object:Gem::Requirement
43
57
  requirements:
44
- - - "~>"
58
+ - - ">="
45
59
  - !ruby/object:Gem::Version
46
60
  version: '1.15'
61
+ - - "<"
62
+ - !ruby/object:Gem::Version
63
+ version: '1.19'
47
64
  type: :runtime
48
65
  prerelease: false
49
66
  version_requirements: !ruby/object:Gem::Requirement
50
67
  requirements:
51
- - - "~>"
68
+ - - ">="
52
69
  - !ruby/object:Gem::Version
53
70
  version: '1.15'
71
+ - - "<"
72
+ - !ruby/object:Gem::Version
73
+ version: '1.19'
54
74
  - !ruby/object:Gem::Dependency
55
75
  name: parslet
56
76
  requirement: !ruby/object:Gem::Requirement
@@ -66,47 +86,47 @@ dependencies:
66
86
  - !ruby/object:Gem::Version
67
87
  version: '2.0'
68
88
  - !ruby/object:Gem::Dependency
69
- name: roo
89
+ name: rack
70
90
  requirement: !ruby/object:Gem::Requirement
71
91
  requirements:
72
92
  - - "~>"
73
93
  - !ruby/object:Gem::Version
74
- version: '2.10'
94
+ version: '2.0'
75
95
  type: :runtime
76
96
  prerelease: false
77
97
  version_requirements: !ruby/object:Gem::Requirement
78
98
  requirements:
79
99
  - - "~>"
80
100
  - !ruby/object:Gem::Version
81
- version: '2.10'
101
+ version: '2.0'
82
102
  - !ruby/object:Gem::Dependency
83
- name: rubyzip
103
+ name: roo
84
104
  requirement: !ruby/object:Gem::Requirement
85
105
  requirements:
86
- - - "<"
106
+ - - "~>"
87
107
  - !ruby/object:Gem::Version
88
- version: 3.0.0
108
+ version: '2.10'
89
109
  type: :runtime
90
110
  prerelease: false
91
111
  version_requirements: !ruby/object:Gem::Requirement
92
112
  requirements:
93
- - - "<"
113
+ - - "~>"
94
114
  - !ruby/object:Gem::Version
95
- version: 3.0.0
115
+ version: '2.10'
96
116
  - !ruby/object:Gem::Dependency
97
- name: sinatra
117
+ name: rubyzip
98
118
  requirement: !ruby/object:Gem::Requirement
99
119
  requirements:
100
- - - "~>"
120
+ - - "<"
101
121
  - !ruby/object:Gem::Version
102
- version: '3.0'
122
+ version: 3.0.0
103
123
  type: :runtime
104
124
  prerelease: false
105
125
  version_requirements: !ruby/object:Gem::Requirement
106
126
  requirements:
107
- - - "~>"
127
+ - - "<"
108
128
  - !ruby/object:Gem::Version
109
- version: '3.0'
129
+ version: 3.0.0
110
130
  - !ruby/object:Gem::Dependency
111
131
  name: rack-test
112
132
  requirement: !ruby/object:Gem::Requirement
@@ -163,6 +183,20 @@ dependencies:
163
183
  - - "~>"
164
184
  - !ruby/object:Gem::Version
165
185
  version: '1.60'
186
+ - !ruby/object:Gem::Dependency
187
+ name: webmock
188
+ requirement: !ruby/object:Gem::Requirement
189
+ requirements:
190
+ - - "~>"
191
+ - !ruby/object:Gem::Version
192
+ version: '3.18'
193
+ type: :development
194
+ prerelease: false
195
+ version_requirements: !ruby/object:Gem::Requirement
196
+ requirements:
197
+ - - "~>"
198
+ - !ruby/object:Gem::Version
199
+ version: '3.18'
166
200
  description: A production-grade decision agent that provides deterministic rule evaluation,
167
201
  conflict resolution, and full audit replay capabilities. Framework-agnostic and
168
202
  AI-optional.
@@ -222,6 +256,30 @@ files:
222
256
  - lib/decision_agent/dmn/versioning.rb
223
257
  - lib/decision_agent/dmn/visualizer.rb
224
258
  - lib/decision_agent/dsl/condition_evaluator.rb
259
+ - lib/decision_agent/dsl/helpers/cache_helpers.rb
260
+ - lib/decision_agent/dsl/helpers/comparison_helpers.rb
261
+ - lib/decision_agent/dsl/helpers/date_helpers.rb
262
+ - lib/decision_agent/dsl/helpers/geospatial_helpers.rb
263
+ - lib/decision_agent/dsl/helpers/operator_evaluation_helpers.rb
264
+ - lib/decision_agent/dsl/helpers/parameter_parsing_helpers.rb
265
+ - lib/decision_agent/dsl/helpers/template_helpers.rb
266
+ - lib/decision_agent/dsl/helpers/utility_helpers.rb
267
+ - lib/decision_agent/dsl/operators/base.rb
268
+ - lib/decision_agent/dsl/operators/basic_comparison_operators.rb
269
+ - lib/decision_agent/dsl/operators/collection_operators.rb
270
+ - lib/decision_agent/dsl/operators/date_arithmetic_operators.rb
271
+ - lib/decision_agent/dsl/operators/date_time_operators.rb
272
+ - lib/decision_agent/dsl/operators/duration_operators.rb
273
+ - lib/decision_agent/dsl/operators/financial_operators.rb
274
+ - lib/decision_agent/dsl/operators/geospatial_operators.rb
275
+ - lib/decision_agent/dsl/operators/mathematical_operators.rb
276
+ - lib/decision_agent/dsl/operators/moving_window_operators.rb
277
+ - lib/decision_agent/dsl/operators/numeric_operators.rb
278
+ - lib/decision_agent/dsl/operators/rate_operators.rb
279
+ - lib/decision_agent/dsl/operators/statistical_aggregations.rb
280
+ - lib/decision_agent/dsl/operators/string_aggregations.rb
281
+ - lib/decision_agent/dsl/operators/string_operators.rb
282
+ - lib/decision_agent/dsl/operators/time_component_operators.rb
225
283
  - lib/decision_agent/dsl/rule_parser.rb
226
284
  - lib/decision_agent/dsl/schema_validator.rb
227
285
  - lib/decision_agent/errors.rb
@@ -231,6 +289,10 @@ files:
231
289
  - lib/decision_agent/evaluators/dmn_evaluator.rb
232
290
  - lib/decision_agent/evaluators/json_rule_evaluator.rb
233
291
  - lib/decision_agent/evaluators/static_evaluator.rb
292
+ - lib/decision_agent/explainability/condition_trace.rb
293
+ - lib/decision_agent/explainability/explainability_result.rb
294
+ - lib/decision_agent/explainability/rule_trace.rb
295
+ - lib/decision_agent/explainability/trace_collector.rb
234
296
  - lib/decision_agent/monitoring/alert_manager.rb
235
297
  - lib/decision_agent/monitoring/dashboard/public/dashboard.css
236
298
  - lib/decision_agent/monitoring/dashboard/public/dashboard.js
@@ -248,6 +310,15 @@ files:
248
310
  - lib/decision_agent/scoring/max_weight.rb
249
311
  - lib/decision_agent/scoring/threshold.rb
250
312
  - lib/decision_agent/scoring/weighted_average.rb
313
+ - lib/decision_agent/simulation.rb
314
+ - lib/decision_agent/simulation/errors.rb
315
+ - lib/decision_agent/simulation/impact_analyzer.rb
316
+ - lib/decision_agent/simulation/monte_carlo_simulator.rb
317
+ - lib/decision_agent/simulation/replay_engine.rb
318
+ - lib/decision_agent/simulation/scenario_engine.rb
319
+ - lib/decision_agent/simulation/scenario_library.rb
320
+ - lib/decision_agent/simulation/shadow_test_engine.rb
321
+ - lib/decision_agent/simulation/what_if_analyzer.rb
251
322
  - lib/decision_agent/testing/batch_test_importer.rb
252
323
  - lib/decision_agent/testing/batch_test_runner.rb
253
324
  - lib/decision_agent/testing/test_coverage_analyzer.rb
@@ -259,6 +330,8 @@ files:
259
330
  - lib/decision_agent/versioning/file_storage_adapter.rb
260
331
  - lib/decision_agent/versioning/version_manager.rb
261
332
  - lib/decision_agent/web/dmn_editor.rb
333
+ - lib/decision_agent/web/dmn_editor/serialization.rb
334
+ - lib/decision_agent/web/dmn_editor/xml_builder.rb
262
335
  - lib/decision_agent/web/middleware/auth_middleware.rb
263
336
  - lib/decision_agent/web/middleware/permission_middleware.rb
264
337
  - lib/decision_agent/web/public/app.js
@@ -268,8 +341,21 @@ files:
268
341
  - lib/decision_agent/web/public/dmn-editor.js
269
342
  - lib/decision_agent/web/public/index.html
270
343
  - lib/decision_agent/web/public/login.html
344
+ - lib/decision_agent/web/public/sample_batch.csv
345
+ - lib/decision_agent/web/public/sample_impact.csv
346
+ - lib/decision_agent/web/public/sample_replay.csv
347
+ - lib/decision_agent/web/public/sample_rules.json
348
+ - lib/decision_agent/web/public/sample_shadow.csv
349
+ - lib/decision_agent/web/public/sample_whatif.csv
350
+ - lib/decision_agent/web/public/simulation.html
351
+ - lib/decision_agent/web/public/simulation_impact.html
352
+ - lib/decision_agent/web/public/simulation_replay.html
353
+ - lib/decision_agent/web/public/simulation_shadow.html
354
+ - lib/decision_agent/web/public/simulation_whatif.html
271
355
  - lib/decision_agent/web/public/styles.css
272
356
  - lib/decision_agent/web/public/users.html
357
+ - lib/decision_agent/web/rack_helpers.rb
358
+ - lib/decision_agent/web/rack_request_helpers.rb
273
359
  - lib/decision_agent/web/server.rb
274
360
  - lib/generators/decision_agent/install/install_generator.rb
275
361
  - lib/generators/decision_agent/install/templates/README
@@ -286,85 +372,13 @@ files:
286
372
  - lib/generators/decision_agent/install/templates/performance_metric.rb
287
373
  - lib/generators/decision_agent/install/templates/rule.rb
288
374
  - lib/generators/decision_agent/install/templates/rule_version.rb
289
- - spec/ab_testing/ab_test_assignment_spec.rb
290
- - spec/ab_testing/ab_test_manager_spec.rb
291
- - spec/ab_testing/ab_test_spec.rb
292
- - spec/ab_testing/ab_testing_agent_spec.rb
293
- - spec/ab_testing/storage/adapter_spec.rb
294
- - spec/ab_testing/storage/memory_adapter_spec.rb
295
- - spec/activerecord_thread_safety_spec.rb
296
- - spec/advanced_operators_spec.rb
297
- - spec/agent_spec.rb
298
- - spec/api_contract_spec.rb
299
- - spec/audit_adapters_spec.rb
300
- - spec/auth/access_audit_logger_spec.rb
301
- - spec/auth/authenticator_spec.rb
302
- - spec/auth/password_reset_spec.rb
303
- - spec/auth/permission_checker_spec.rb
304
- - spec/auth/permission_spec.rb
305
- - spec/auth/rbac_adapter_spec.rb
306
- - spec/auth/rbac_config_spec.rb
307
- - spec/auth/role_spec.rb
308
- - spec/auth/session_manager_spec.rb
309
- - spec/auth/session_spec.rb
310
- - spec/auth/user_spec.rb
311
- - spec/comprehensive_edge_cases_spec.rb
312
- - spec/context_spec.rb
313
- - spec/decision_agent_spec.rb
314
- - spec/decision_spec.rb
315
- - spec/dmn/decision_graph_spec.rb
316
- - spec/dmn/decision_tree_spec.rb
317
- - spec/dmn/feel/errors_spec.rb
318
- - spec/dmn/feel/functions_spec.rb
319
- - spec/dmn/feel/simple_parser_spec.rb
320
- - spec/dmn/feel/types_spec.rb
321
- - spec/dmn/feel_parser_spec.rb
322
- - spec/dmn/hit_policy_spec.rb
323
- - spec/dmn/integration_spec.rb
324
- - spec/dsl/condition_evaluator_spec.rb
325
- - spec/dsl_validation_spec.rb
326
- - spec/edge_cases_spec.rb
327
- - spec/evaluation_spec.rb
328
- - spec/evaluation_validator_spec.rb
329
- - spec/examples.txt
330
- - spec/examples/feedback_aware_evaluator_spec.rb
331
- - spec/fixtures/dmn/complex_decision.dmn
332
- - spec/fixtures/dmn/invalid_structure.dmn
333
- - spec/fixtures/dmn/simple_decision.dmn
334
- - spec/issue_verification_spec.rb
335
- - spec/json_rule_evaluator_spec.rb
336
- - spec/monitoring/alert_manager_spec.rb
337
- - spec/monitoring/metrics_collector_spec.rb
338
- - spec/monitoring/monitored_agent_spec.rb
339
- - spec/monitoring/prometheus_exporter_spec.rb
340
- - spec/monitoring/storage/activerecord_adapter_spec.rb
341
- - spec/monitoring/storage/base_adapter_spec.rb
342
- - spec/monitoring/storage/memory_adapter_spec.rb
343
- - spec/performance_optimizations_spec.rb
344
- - spec/replay_edge_cases_spec.rb
345
- - spec/replay_spec.rb
346
- - spec/rfc8785_canonicalization_spec.rb
347
- - spec/scoring_spec.rb
348
- - spec/spec_helper.rb
349
- - spec/testing/batch_test_importer_spec.rb
350
- - spec/testing/batch_test_runner_spec.rb
351
- - spec/testing/test_coverage_analyzer_spec.rb
352
- - spec/testing/test_result_comparator_spec.rb
353
- - spec/testing/test_scenario_spec.rb
354
- - spec/thread_safety_spec.rb
355
- - spec/thread_safety_spec.rb.broken
356
- - spec/versioning/adapter_spec.rb
357
- - spec/versioning_spec.rb
358
- - spec/web/middleware/auth_middleware_spec.rb
359
- - spec/web/middleware/permission_middleware_spec.rb
360
- - spec/web_ui_rack_spec.rb
361
375
  homepage: https://github.com/samaswin/decision_agent
362
376
  licenses:
363
377
  - MIT
364
378
  metadata:
365
379
  homepage_uri: https://github.com/samaswin/decision_agent
366
380
  source_code_uri: https://github.com/samaswin/decision_agent
367
- changelog_uri: https://github.com/samaswin/decision_agent/blob/main/CHANGELOG.md
381
+ changelog_uri: https://github.com/samaswin/decision_agent/blob/main/docs/CHANGELOG.md
368
382
  github_repo: https://github.com/samaswin/decision_agent
369
383
  rubygems_mfa_required: 'true'
370
384
  rdoc_options: []
@@ -1,253 +0,0 @@
1
- require "spec_helper"
2
- require "decision_agent/ab_testing/ab_test_assignment"
3
-
4
- RSpec.describe DecisionAgent::ABTesting::ABTestAssignment do
5
- describe "#initialize" do
6
- it "creates an assignment with required fields" do
7
- assignment = described_class.new(
8
- ab_test_id: "test_1",
9
- variant: :champion,
10
- version_id: "v1"
11
- )
12
-
13
- expect(assignment.ab_test_id).to eq("test_1")
14
- expect(assignment.variant).to eq(:champion)
15
- expect(assignment.version_id).to eq("v1")
16
- expect(assignment.timestamp).to be_a(Time)
17
- end
18
-
19
- it "accepts optional user_id" do
20
- assignment = described_class.new(
21
- ab_test_id: "test_1",
22
- variant: :champion,
23
- version_id: "v1",
24
- user_id: "user_123"
25
- )
26
-
27
- expect(assignment.user_id).to eq("user_123")
28
- end
29
-
30
- it "accepts optional timestamp" do
31
- custom_time = Time.new(2024, 1, 1, 12, 0, 0, "+00:00")
32
- assignment = described_class.new(
33
- ab_test_id: "test_1",
34
- variant: :champion,
35
- version_id: "v1",
36
- timestamp: custom_time
37
- )
38
-
39
- expect(assignment.timestamp).to eq(custom_time)
40
- end
41
-
42
- it "accepts optional decision_result and confidence" do
43
- assignment = described_class.new(
44
- ab_test_id: "test_1",
45
- variant: :champion,
46
- version_id: "v1",
47
- decision_result: "approve",
48
- confidence: 0.95
49
- )
50
-
51
- expect(assignment.decision_result).to eq("approve")
52
- expect(assignment.confidence).to eq(0.95)
53
- end
54
-
55
- it "accepts optional context" do
56
- context = { user_type: "premium", region: "us" }
57
- assignment = described_class.new(
58
- ab_test_id: "test_1",
59
- variant: :champion,
60
- version_id: "v1",
61
- context: context
62
- )
63
-
64
- expect(assignment.context).to eq(context)
65
- end
66
-
67
- it "defaults context to empty hash" do
68
- assignment = described_class.new(
69
- ab_test_id: "test_1",
70
- variant: :champion,
71
- version_id: "v1"
72
- )
73
-
74
- expect(assignment.context).to eq({})
75
- end
76
-
77
- it "accepts optional id" do
78
- assignment = described_class.new(
79
- ab_test_id: "test_1",
80
- variant: :champion,
81
- version_id: "v1",
82
- id: "assign_123"
83
- )
84
-
85
- expect(assignment.id).to eq("assign_123")
86
- end
87
-
88
- it "raises error if ab_test_id is nil" do
89
- expect do
90
- described_class.new(
91
- ab_test_id: nil,
92
- variant: :champion,
93
- version_id: "v1"
94
- )
95
- end.to raise_error(DecisionAgent::ValidationError, /AB test ID is required/)
96
- end
97
-
98
- it "raises error if variant is nil" do
99
- expect do
100
- described_class.new(
101
- ab_test_id: "test_1",
102
- variant: nil,
103
- version_id: "v1"
104
- )
105
- end.to raise_error(DecisionAgent::ValidationError, /Variant is required/)
106
- end
107
-
108
- it "raises error if version_id is nil" do
109
- expect do
110
- described_class.new(
111
- ab_test_id: "test_1",
112
- variant: :champion,
113
- version_id: nil
114
- )
115
- end.to raise_error(DecisionAgent::ValidationError, /Version ID is required/)
116
- end
117
-
118
- it "raises error if variant is not :champion or :challenger" do
119
- expect do
120
- described_class.new(
121
- ab_test_id: "test_1",
122
- variant: :invalid,
123
- version_id: "v1"
124
- )
125
- end.to raise_error(DecisionAgent::ValidationError, /Variant must be :champion or :challenger/)
126
- end
127
-
128
- it "raises error if confidence is negative" do
129
- expect do
130
- described_class.new(
131
- ab_test_id: "test_1",
132
- variant: :champion,
133
- version_id: "v1",
134
- confidence: -0.1
135
- )
136
- end.to raise_error(DecisionAgent::ValidationError, /Confidence must be between 0 and 1/)
137
- end
138
-
139
- it "raises error if confidence is greater than 1" do
140
- expect do
141
- described_class.new(
142
- ab_test_id: "test_1",
143
- variant: :champion,
144
- version_id: "v1",
145
- confidence: 1.5
146
- )
147
- end.to raise_error(DecisionAgent::ValidationError, /Confidence must be between 0 and 1/)
148
- end
149
-
150
- it "accepts confidence of 0" do
151
- assignment = described_class.new(
152
- ab_test_id: "test_1",
153
- variant: :champion,
154
- version_id: "v1",
155
- confidence: 0.0
156
- )
157
-
158
- expect(assignment.confidence).to eq(0.0)
159
- end
160
-
161
- it "accepts confidence of 1" do
162
- assignment = described_class.new(
163
- ab_test_id: "test_1",
164
- variant: :champion,
165
- version_id: "v1",
166
- confidence: 1.0
167
- )
168
-
169
- expect(assignment.confidence).to eq(1.0)
170
- end
171
-
172
- it "accepts challenger variant" do
173
- assignment = described_class.new(
174
- ab_test_id: "test_1",
175
- variant: :challenger,
176
- version_id: "v2"
177
- )
178
-
179
- expect(assignment.variant).to eq(:challenger)
180
- end
181
- end
182
-
183
- describe "#record_decision" do
184
- let(:assignment) do
185
- described_class.new(
186
- ab_test_id: "test_1",
187
- variant: :champion,
188
- version_id: "v1"
189
- )
190
- end
191
-
192
- it "updates decision_result and confidence" do
193
- assignment.record_decision("approve", 0.95)
194
-
195
- expect(assignment.decision_result).to eq("approve")
196
- expect(assignment.confidence).to eq(0.95)
197
- end
198
-
199
- it "can update multiple times" do
200
- assignment.record_decision("approve", 0.95)
201
- assignment.record_decision("reject", 0.85)
202
-
203
- expect(assignment.decision_result).to eq("reject")
204
- expect(assignment.confidence).to eq(0.85)
205
- end
206
- end
207
-
208
- describe "#to_h" do
209
- it "converts assignment to hash with all fields" do
210
- assignment = described_class.new(
211
- ab_test_id: "test_1",
212
- variant: :champion,
213
- version_id: "v1",
214
- id: "assign_123",
215
- user_id: "user_456",
216
- decision_result: "approve",
217
- confidence: 0.95,
218
- context: { region: "us" },
219
- timestamp: Time.new(2024, 1, 1, 12, 0, 0, "+00:00")
220
- )
221
-
222
- hash = assignment.to_h
223
-
224
- expect(hash).to eq({
225
- id: "assign_123",
226
- ab_test_id: "test_1",
227
- user_id: "user_456",
228
- variant: :champion,
229
- version_id: "v1",
230
- timestamp: Time.new(2024, 1, 1, 12, 0, 0, "+00:00"),
231
- decision_result: "approve",
232
- confidence: 0.95,
233
- context: { region: "us" }
234
- })
235
- end
236
-
237
- it "includes nil values in hash" do
238
- assignment = described_class.new(
239
- ab_test_id: "test_1",
240
- variant: :champion,
241
- version_id: "v1"
242
- )
243
-
244
- hash = assignment.to_h
245
-
246
- expect(hash[:id]).to be_nil
247
- expect(hash[:user_id]).to be_nil
248
- expect(hash[:decision_result]).to be_nil
249
- expect(hash[:confidence]).to be_nil
250
- expect(hash[:context]).to eq({})
251
- end
252
- end
253
- end