decision_agent 0.1.2 → 0.1.3

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 (63) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +212 -35
  3. data/bin/decision_agent +3 -8
  4. data/lib/decision_agent/agent.rb +19 -26
  5. data/lib/decision_agent/audit/null_adapter.rb +1 -2
  6. data/lib/decision_agent/decision.rb +3 -1
  7. data/lib/decision_agent/dsl/condition_evaluator.rb +4 -3
  8. data/lib/decision_agent/dsl/rule_parser.rb +4 -6
  9. data/lib/decision_agent/dsl/schema_validator.rb +27 -31
  10. data/lib/decision_agent/errors.rb +11 -8
  11. data/lib/decision_agent/evaluation.rb +3 -1
  12. data/lib/decision_agent/evaluation_validator.rb +78 -0
  13. data/lib/decision_agent/evaluators/json_rule_evaluator.rb +26 -0
  14. data/lib/decision_agent/evaluators/static_evaluator.rb +2 -6
  15. data/lib/decision_agent/monitoring/alert_manager.rb +282 -0
  16. data/lib/decision_agent/monitoring/dashboard/public/dashboard.css +381 -0
  17. data/lib/decision_agent/monitoring/dashboard/public/dashboard.js +471 -0
  18. data/lib/decision_agent/monitoring/dashboard/public/index.html +161 -0
  19. data/lib/decision_agent/monitoring/dashboard_server.rb +340 -0
  20. data/lib/decision_agent/monitoring/metrics_collector.rb +278 -0
  21. data/lib/decision_agent/monitoring/monitored_agent.rb +71 -0
  22. data/lib/decision_agent/monitoring/prometheus_exporter.rb +247 -0
  23. data/lib/decision_agent/replay/replay.rb +12 -22
  24. data/lib/decision_agent/scoring/base.rb +1 -1
  25. data/lib/decision_agent/scoring/consensus.rb +5 -5
  26. data/lib/decision_agent/scoring/weighted_average.rb +1 -1
  27. data/lib/decision_agent/version.rb +1 -1
  28. data/lib/decision_agent/versioning/activerecord_adapter.rb +69 -33
  29. data/lib/decision_agent/versioning/adapter.rb +1 -3
  30. data/lib/decision_agent/versioning/file_storage_adapter.rb +143 -35
  31. data/lib/decision_agent/versioning/version_manager.rb +4 -12
  32. data/lib/decision_agent/web/public/index.html +1 -1
  33. data/lib/decision_agent/web/server.rb +19 -24
  34. data/lib/decision_agent.rb +7 -0
  35. data/lib/generators/decision_agent/install/install_generator.rb +5 -5
  36. data/lib/generators/decision_agent/install/templates/migration.rb +17 -6
  37. data/lib/generators/decision_agent/install/templates/rule.rb +3 -3
  38. data/lib/generators/decision_agent/install/templates/rule_version.rb +13 -7
  39. data/spec/activerecord_thread_safety_spec.rb +553 -0
  40. data/spec/agent_spec.rb +13 -13
  41. data/spec/api_contract_spec.rb +16 -16
  42. data/spec/audit_adapters_spec.rb +3 -3
  43. data/spec/comprehensive_edge_cases_spec.rb +86 -86
  44. data/spec/dsl_validation_spec.rb +83 -83
  45. data/spec/edge_cases_spec.rb +23 -23
  46. data/spec/examples/feedback_aware_evaluator_spec.rb +7 -7
  47. data/spec/examples.txt +548 -0
  48. data/spec/issue_verification_spec.rb +685 -0
  49. data/spec/json_rule_evaluator_spec.rb +15 -15
  50. data/spec/monitoring/alert_manager_spec.rb +378 -0
  51. data/spec/monitoring/metrics_collector_spec.rb +281 -0
  52. data/spec/monitoring/monitored_agent_spec.rb +222 -0
  53. data/spec/monitoring/prometheus_exporter_spec.rb +242 -0
  54. data/spec/replay_edge_cases_spec.rb +58 -58
  55. data/spec/replay_spec.rb +11 -11
  56. data/spec/rfc8785_canonicalization_spec.rb +215 -0
  57. data/spec/scoring_spec.rb +1 -1
  58. data/spec/spec_helper.rb +9 -0
  59. data/spec/thread_safety_spec.rb +482 -0
  60. data/spec/thread_safety_spec.rb.broken +878 -0
  61. data/spec/versioning_spec.rb +141 -37
  62. data/spec/web_ui_rack_spec.rb +135 -0
  63. metadata +69 -6
@@ -156,9 +156,9 @@ RSpec.describe "DecisionAgent Versioning System" do
156
156
  end
157
157
 
158
158
  it "raises error for nonexistent version" do
159
- expect {
159
+ expect do
160
160
  adapter.activate_version(version_id: "nonexistent")
161
- }.to raise_error(DecisionAgent::NotFoundError)
161
+ end.to raise_error(DecisionAgent::NotFoundError)
162
162
  end
163
163
  end
164
164
 
@@ -227,17 +227,17 @@ RSpec.describe "DecisionAgent Versioning System" do
227
227
  end
228
228
 
229
229
  it "validates rule content" do
230
- expect {
230
+ expect do
231
231
  manager.save_version(rule_id: rule_id, rule_content: nil)
232
- }.to raise_error(DecisionAgent::ValidationError, /cannot be nil/)
232
+ end.to raise_error(DecisionAgent::ValidationError, /cannot be nil/)
233
233
 
234
- expect {
234
+ expect do
235
235
  manager.save_version(rule_id: rule_id, rule_content: "not a hash")
236
- }.to raise_error(DecisionAgent::ValidationError, /must be a Hash/)
236
+ end.to raise_error(DecisionAgent::ValidationError, /must be a Hash/)
237
237
 
238
- expect {
238
+ expect do
239
239
  manager.save_version(rule_id: rule_id, rule_content: {})
240
- }.to raise_error(DecisionAgent::ValidationError, /cannot be empty/)
240
+ end.to raise_error(DecisionAgent::ValidationError, /cannot be empty/)
241
241
  end
242
242
 
243
243
  it "generates default changelog if not provided" do
@@ -263,18 +263,48 @@ RSpec.describe "DecisionAgent Versioning System" do
263
263
  end
264
264
 
265
265
  describe "#rollback" do
266
- it "activates a previous version and creates new version" do
266
+ it "activates a previous version without creating a duplicate" do
267
267
  v1 = manager.save_version(rule_id: rule_id, rule_content: rule_content, changelog: "v1")
268
268
  manager.save_version(rule_id: rule_id, rule_content: rule_content, changelog: "v2")
269
+ manager.save_version(rule_id: rule_id, rule_content: rule_content, changelog: "v3")
269
270
 
271
+ # Rollback to v1 should just activate it, not create a duplicate
270
272
  rolled_back = manager.rollback(version_id: v1[:id], performed_by: "admin")
271
273
 
272
274
  expect(rolled_back[:status]).to eq("active")
275
+ expect(rolled_back[:id]).to eq(v1[:id])
273
276
 
274
- # Should create a new version documenting the rollback
277
+ # Should NOT create a new version - just activate the old one
275
278
  versions = manager.get_versions(rule_id: rule_id)
276
- expect(versions.length).to eq(3) # v1, v2, and rollback version
277
- expect(versions.first[:changelog]).to include("Rolled back")
279
+ expect(versions.length).to eq(3) # Still just v1, v2, v3
280
+
281
+ # v1 should be active, v2 and v3 should be archived
282
+ active_version = manager.get_active_version(rule_id: rule_id)
283
+ expect(active_version[:id]).to eq(v1[:id])
284
+ expect(active_version[:version_number]).to eq(1)
285
+ end
286
+
287
+ it "maintains version history integrity after rollback" do
288
+ v1 = manager.save_version(rule_id: rule_id, rule_content: rule_content.merge(data: "v1"), changelog: "Version 1")
289
+ v2 = manager.save_version(rule_id: rule_id, rule_content: rule_content.merge(data: "v2"), changelog: "Version 2")
290
+ v3 = manager.save_version(rule_id: rule_id, rule_content: rule_content.merge(data: "v3"), changelog: "Version 3")
291
+
292
+ # Rollback to v2
293
+ manager.rollback(version_id: v2[:id])
294
+
295
+ # All original versions should still exist with original data
296
+ loaded_v1 = manager.get_version(version_id: v1[:id])
297
+ loaded_v2 = manager.get_version(version_id: v2[:id])
298
+ loaded_v3 = manager.get_version(version_id: v3[:id])
299
+
300
+ expect(loaded_v1[:content][:data]).to eq("v1")
301
+ expect(loaded_v2[:content][:data]).to eq("v2")
302
+ expect(loaded_v3[:content][:data]).to eq("v3")
303
+
304
+ # v2 should be active
305
+ expect(loaded_v2[:status]).to eq("active")
306
+ expect(loaded_v1[:status]).to eq("archived")
307
+ expect(loaded_v3[:status]).to eq("archived")
278
308
  end
279
309
  end
280
310
 
@@ -296,9 +326,9 @@ RSpec.describe "DecisionAgent Versioning System" do
296
326
 
297
327
  describe "edge cases and error handling" do
298
328
  it "handles empty rule_id gracefully" do
299
- expect {
329
+ expect do
300
330
  manager.save_version(rule_id: "", rule_content: rule_content)
301
- }.not_to raise_error
331
+ end.not_to raise_error
302
332
  end
303
333
 
304
334
  it "handles special characters in rule_id" do
@@ -390,7 +420,7 @@ RSpec.describe "DecisionAgent Versioning System" do
390
420
  Thread.new do
391
421
  manager.save_version(
392
422
  rule_id: rule_id,
393
- rule_content: rule_content.merge(version: "#{i}"),
423
+ rule_content: rule_content.merge(version: i.to_s),
394
424
  created_by: "thread_#{i}"
395
425
  )
396
426
  end
@@ -450,13 +480,13 @@ RSpec.describe "DecisionAgent Versioning System" do
450
480
  }
451
481
 
452
482
  content_v2 = {
453
- version: "2.0", # changed
483
+ version: "2.0", # changed
454
484
  ruleset: "test",
455
485
  rules: [
456
- { id: "rule_1", if: { field: "a", op: "eq", value: 2 }, then: { decision: "reject", weight: 0.9, reason: "Updated" } }, # modified
457
- { id: "rule_2", if: { field: "b", op: "gt", value: 100 }, then: { decision: "approve", weight: 0.7, reason: "New" } } # added
486
+ { id: "rule_1", if: { field: "a", op: "eq", value: 2 }, then: { decision: "reject", weight: 0.9, reason: "Updated" } }, # modified
487
+ { id: "rule_2", if: { field: "b", op: "gt", value: 100 }, then: { decision: "approve", weight: 0.7, reason: "New" } } # added
458
488
  ],
459
- new_field: "added" # added field
489
+ new_field: "added" # added field
460
490
  }
461
491
 
462
492
  v1 = manager.save_version(rule_id: rule_id, rule_content: content_v1)
@@ -470,7 +500,7 @@ RSpec.describe "DecisionAgent Versioning System" do
470
500
  end
471
501
 
472
502
  describe "rollback scenarios" do
473
- it "creates proper audit trail on rollback" do
503
+ it "activates previous version without creating duplicates" do
474
504
  v1 = manager.save_version(rule_id: rule_id, rule_content: rule_content, changelog: "Version 1")
475
505
  manager.save_version(rule_id: rule_id, rule_content: rule_content, changelog: "Version 2")
476
506
  manager.save_version(rule_id: rule_id, rule_content: rule_content, changelog: "Version 3")
@@ -478,26 +508,33 @@ RSpec.describe "DecisionAgent Versioning System" do
478
508
  manager.rollback(version_id: v1[:id], performed_by: "admin")
479
509
 
480
510
  history = manager.get_history(rule_id: rule_id)
481
- expect(history[:total_versions]).to eq(4) # v1, v2, v3, rollback version
511
+ expect(history[:total_versions]).to eq(3) # Still just v1, v2, v3 - no duplicate
482
512
 
483
- rollback_version = history[:versions].first
484
- expect(rollback_version[:changelog]).to include("Rolled back")
485
- expect(rollback_version[:changelog]).to include("version 1")
513
+ # v1 should be the active version
514
+ expect(history[:active_version][:id]).to eq(v1[:id])
515
+ expect(history[:active_version][:changelog]).to eq("Version 1")
486
516
  end
487
517
 
488
- it "handles multiple consecutive rollbacks" do
518
+ it "handles multiple consecutive rollbacks without duplication" do
489
519
  v1 = manager.save_version(rule_id: rule_id, rule_content: rule_content)
490
520
  v2 = manager.save_version(rule_id: rule_id, rule_content: rule_content)
491
- manager.save_version(rule_id: rule_id, rule_content: rule_content)
521
+ v3 = manager.save_version(rule_id: rule_id, rule_content: rule_content)
492
522
 
493
523
  # Rollback to v1
494
- manager.rollback(version_id: v1[:id], performed_by: "user1")
524
+ result1 = manager.rollback(version_id: v1[:id], performed_by: "user1")
525
+ expect(result1[:id]).to eq(v1[:id])
495
526
 
496
527
  # Rollback to v2
497
- manager.rollback(version_id: v2[:id], performed_by: "user2")
528
+ result2 = manager.rollback(version_id: v2[:id], performed_by: "user2")
529
+ expect(result2[:id]).to eq(v2[:id])
530
+
531
+ # Rollback to v3
532
+ result3 = manager.rollback(version_id: v3[:id], performed_by: "user3")
533
+ expect(result3[:id]).to eq(v3[:id])
498
534
 
499
535
  history = manager.get_history(rule_id: rule_id)
500
- expect(history[:total_versions]).to eq(5) # Original 3 + 2 rollback versions
536
+ expect(history[:total_versions]).to eq(3) # Still just the original 3 versions
537
+ expect(history[:active_version][:id]).to eq(v3[:id])
501
538
  end
502
539
  end
503
540
 
@@ -517,13 +554,11 @@ RSpec.describe "DecisionAgent Versioning System" do
517
554
  end
518
555
 
519
556
  it "handles versions across multiple rules" do
520
- rule_ids = ["rule_a", "rule_b", "rule_c"]
557
+ rule_ids = %w[rule_a rule_b rule_c]
521
558
 
522
559
  rule_ids.each do |rid|
523
560
  3.times { manager.save_version(rule_id: rid, rule_content: rule_content) }
524
- end
525
561
 
526
- rule_ids.each do |rid|
527
562
  versions = manager.get_versions(rule_id: rid)
528
563
  expect(versions.length).to eq(3)
529
564
  expect(versions.all? { |v| v[:rule_id] == rid }).to be true
@@ -537,7 +572,7 @@ RSpec.describe "DecisionAgent Versioning System" do
537
572
  manager.save_version(rule_id: rule_id, rule_content: rule_content)
538
573
 
539
574
  begin
540
- manager.save_version(rule_id: rule_id, rule_content: nil) # This should fail
575
+ manager.save_version(rule_id: rule_id, rule_content: nil) # This should fail
541
576
  rescue DecisionAgent::ValidationError
542
577
  # Expected error
543
578
  end
@@ -623,11 +658,12 @@ RSpec.describe "DecisionAgent Versioning System" do
623
658
  )
624
659
 
625
660
  expect(rolled_back[:status]).to eq("active")
661
+ expect(rolled_back[:id]).to eq(v2[:id])
626
662
 
627
663
  # 6. Verify history
628
664
  history = manager.get_history(rule_id: "approval_001")
629
- expect(history[:total_versions]).to eq(4) # v1, v2, v3, rollback
630
- expect(history[:active_version][:version_number]).to be > 3
665
+ expect(history[:total_versions]).to eq(3) # v1, v2, v3 - no duplicate created
666
+ expect(history[:active_version][:version_number]).to eq(2) # v2 is active
631
667
  end
632
668
  end
633
669
 
@@ -647,7 +683,7 @@ RSpec.describe "DecisionAgent Versioning System" do
647
683
  "review" => {
648
684
  version: "1.0",
649
685
  ruleset: "review",
650
- rules: [{ id: "review_1", if: { field: "amount", op: "gte", value: 10000 }, then: { decision: "manual_review", weight: 0.9, reason: "Large transaction" } }]
686
+ rules: [{ id: "review_1", if: { field: "amount", op: "gte", value: 10_000 }, then: { decision: "manual_review", weight: 0.9, reason: "Large transaction" } }]
651
687
  }
652
688
  }
653
689
 
@@ -662,12 +698,80 @@ RSpec.describe "DecisionAgent Versioning System" do
662
698
  end
663
699
 
664
700
  # Verify each has its own version history
665
- rulesets.keys.each do |name|
701
+ rulesets.each_key do |name|
666
702
  history = manager.get_history(rule_id: name)
667
703
  expect(history[:total_versions]).to eq(1)
668
704
  expect(history[:active_version][:rule_id]).to eq(name)
669
705
  end
670
706
  end
671
707
  end
708
+
709
+ describe "status validation" do
710
+ let(:rule_id) { "test_status_rule" }
711
+ let(:rule_content) do
712
+ {
713
+ version: "1.0",
714
+ ruleset: "test",
715
+ rules: [{ id: "test", if: { field: "x", op: "eq", value: 1 }, then: { decision: "approve", weight: 0.8, reason: "Test" } }]
716
+ }
717
+ end
718
+
719
+ it "rejects invalid status values when creating versions" do
720
+ expect do
721
+ adapter.create_version(
722
+ rule_id: rule_id,
723
+ content: rule_content,
724
+ metadata: { status: "banana" }
725
+ )
726
+ end.to raise_error(DecisionAgent::ValidationError, /Invalid status 'banana'/)
727
+
728
+ expect do
729
+ adapter.create_version(
730
+ rule_id: rule_id,
731
+ content: rule_content,
732
+ metadata: { status: "pending" }
733
+ )
734
+ end.to raise_error(DecisionAgent::ValidationError, /Invalid status 'pending'/)
735
+
736
+ expect do
737
+ adapter.create_version(
738
+ rule_id: rule_id,
739
+ content: rule_content,
740
+ metadata: { status: "deleted" }
741
+ )
742
+ end.to raise_error(DecisionAgent::ValidationError, /Invalid status 'deleted'/)
743
+ end
744
+
745
+ it "accepts valid status values" do
746
+ v1 = adapter.create_version(
747
+ rule_id: rule_id,
748
+ content: rule_content,
749
+ metadata: { status: "draft" }
750
+ )
751
+ expect(v1[:status]).to eq("draft")
752
+
753
+ v2 = adapter.create_version(
754
+ rule_id: "rule_002",
755
+ content: rule_content,
756
+ metadata: { status: "active" }
757
+ )
758
+ expect(v2[:status]).to eq("active")
759
+
760
+ v3 = adapter.create_version(
761
+ rule_id: "rule_003",
762
+ content: rule_content,
763
+ metadata: { status: "archived" }
764
+ )
765
+ expect(v3[:status]).to eq("archived")
766
+ end
767
+
768
+ it "uses default status 'active' when not provided" do
769
+ version = adapter.create_version(
770
+ rule_id: rule_id,
771
+ content: rule_content
772
+ )
773
+ expect(version[:status]).to eq("active")
774
+ end
775
+ end
672
776
  end
673
777
  end
@@ -0,0 +1,135 @@
1
+ require "spec_helper"
2
+ require "rack/test"
3
+ require_relative "../lib/decision_agent/web/server"
4
+
5
+ RSpec.describe "DecisionAgent Web UI Rack Integration" do
6
+ include Rack::Test::Methods
7
+
8
+ def app
9
+ DecisionAgent::Web::Server
10
+ end
11
+
12
+ describe "Rack interface" do
13
+ it "responds to .call for Rack compatibility" do
14
+ expect(DecisionAgent::Web::Server).to respond_to(:call)
15
+ end
16
+
17
+ it "serves the main page" do
18
+ get "/"
19
+ expect(last_response).to be_ok
20
+ expect(last_response.body).to include("DecisionAgent")
21
+ end
22
+
23
+ it "serves the health endpoint" do
24
+ get "/health"
25
+ expect(last_response).to be_ok
26
+ expect(last_response.content_type).to include("application/json")
27
+
28
+ json = JSON.parse(last_response.body)
29
+ expect(json["status"]).to eq("ok")
30
+ expect(json["version"]).to eq(DecisionAgent::VERSION)
31
+ end
32
+
33
+ it "validates rules via POST /api/validate" do
34
+ valid_rules = {
35
+ version: "1.0",
36
+ ruleset: "test_rules",
37
+ rules: [{
38
+ id: "test_rule",
39
+ if: { field: "amount", op: "gt", value: 100 },
40
+ then: { decision: "approve", weight: 0.9, reason: "Test" }
41
+ }]
42
+ }
43
+
44
+ post "/api/validate", valid_rules.to_json, { "CONTENT_TYPE" => "application/json" }
45
+
46
+ expect(last_response).to be_ok
47
+ json = JSON.parse(last_response.body)
48
+ expect(json["valid"]).to be true
49
+ end
50
+
51
+ it "returns error for invalid rules" do
52
+ invalid_rules = {
53
+ version: "1.0",
54
+ ruleset: "test_rules",
55
+ rules: [{
56
+ id: "bad_rule"
57
+ # Missing required fields
58
+ }]
59
+ }
60
+
61
+ post "/api/validate", invalid_rules.to_json, { "CONTENT_TYPE" => "application/json" }
62
+
63
+ expect(last_response.status).to eq(422)
64
+ json = JSON.parse(last_response.body)
65
+ expect(json["valid"]).to be false
66
+ expect(json["errors"]).to be_an(Array)
67
+ end
68
+
69
+ it "evaluates rules via POST /api/evaluate" do
70
+ rules = {
71
+ version: "1.0",
72
+ ruleset: "test_rules",
73
+ rules: [{
74
+ id: "high_value",
75
+ if: { field: "amount", op: "gt", value: 1000 },
76
+ then: { decision: "approve", weight: 0.9, reason: "High value" }
77
+ }]
78
+ }
79
+
80
+ payload = {
81
+ rules: rules,
82
+ context: { amount: 1500 }
83
+ }
84
+
85
+ post "/api/evaluate", payload.to_json, { "CONTENT_TYPE" => "application/json" }
86
+
87
+ expect(last_response).to be_ok
88
+ json = JSON.parse(last_response.body)
89
+ expect(json["success"]).to be true
90
+ expect(json["decision"]).to eq("approve")
91
+ expect(json["weight"]).to eq(0.9)
92
+ expect(json["reason"]).to eq("High value")
93
+ end
94
+
95
+ it "serves example rules" do
96
+ get "/api/examples"
97
+
98
+ expect(last_response).to be_ok
99
+ json = JSON.parse(last_response.body)
100
+ expect(json).to be_an(Array)
101
+ expect(json.length).to be > 0
102
+ expect(json.first).to have_key("name")
103
+ expect(json.first).to have_key("rules")
104
+ end
105
+
106
+ it "handles CORS preflight requests" do
107
+ options "/api/validate"
108
+
109
+ expect(last_response.status).to eq(200)
110
+ expect(last_response.headers["Access-Control-Allow-Origin"]).to eq("*")
111
+ expect(last_response.headers["Access-Control-Allow-Methods"]).to include("POST")
112
+ end
113
+ end
114
+
115
+ describe "Rails mounting compatibility" do
116
+ it "can be mounted in a Rack app" do
117
+ # Simulate a Rails-style mount
118
+ rack_app = Rack::Builder.new do
119
+ map "/decision_agent" do
120
+ run DecisionAgent::Web::Server
121
+ end
122
+ end
123
+
124
+ # Create a test session for the mounted app
125
+ test_session = Rack::Test::Session.new(Rack::MockSession.new(rack_app))
126
+
127
+ # Test that the health endpoint works when mounted
128
+ test_session.get "/decision_agent/health"
129
+ expect(test_session.last_response).to be_ok
130
+
131
+ json = JSON.parse(test_session.last_response.body)
132
+ expect(json["status"]).to eq("ok")
133
+ end
134
+ end
135
+ end
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: decision_agent
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.1.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sam Aswin
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-12-20 00:00:00.000000000 Z
11
+ date: 2025-12-24 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: json-canonicalization
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.0'
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: sinatra
15
29
  requirement: !ruby/object:Gem::Requirement
@@ -25,19 +39,19 @@ dependencies:
25
39
  - !ruby/object:Gem::Version
26
40
  version: '3.0'
27
41
  - !ruby/object:Gem::Dependency
28
- name: rspec
42
+ name: rack-test
29
43
  requirement: !ruby/object:Gem::Requirement
30
44
  requirements:
31
45
  - - "~>"
32
46
  - !ruby/object:Gem::Version
33
- version: '3.12'
47
+ version: '2.0'
34
48
  type: :development
35
49
  prerelease: false
36
50
  version_requirements: !ruby/object:Gem::Requirement
37
51
  requirements:
38
52
  - - "~>"
39
53
  - !ruby/object:Gem::Version
40
- version: '3.12'
54
+ version: '2.0'
41
55
  - !ruby/object:Gem::Dependency
42
56
  name: rake
43
57
  requirement: !ruby/object:Gem::Requirement
@@ -52,11 +66,39 @@ dependencies:
52
66
  - - "~>"
53
67
  - !ruby/object:Gem::Version
54
68
  version: '13.0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rspec
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '3.12'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '3.12'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rubocop
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '1.60'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '1.60'
55
97
  description: A production-grade decision agent that provides deterministic rule evaluation,
56
98
  conflict resolution, and full audit replay capabilities. Framework-agnostic and
57
99
  AI-optional.
58
100
  email:
59
- - samaswin87@gmail.com
101
+ - samaswin@gmail.com
60
102
  executables:
61
103
  - decision_agent
62
104
  extensions: []
@@ -77,9 +119,18 @@ files:
77
119
  - lib/decision_agent/dsl/schema_validator.rb
78
120
  - lib/decision_agent/errors.rb
79
121
  - lib/decision_agent/evaluation.rb
122
+ - lib/decision_agent/evaluation_validator.rb
80
123
  - lib/decision_agent/evaluators/base.rb
81
124
  - lib/decision_agent/evaluators/json_rule_evaluator.rb
82
125
  - lib/decision_agent/evaluators/static_evaluator.rb
126
+ - lib/decision_agent/monitoring/alert_manager.rb
127
+ - lib/decision_agent/monitoring/dashboard/public/dashboard.css
128
+ - lib/decision_agent/monitoring/dashboard/public/dashboard.js
129
+ - lib/decision_agent/monitoring/dashboard/public/index.html
130
+ - lib/decision_agent/monitoring/dashboard_server.rb
131
+ - lib/decision_agent/monitoring/metrics_collector.rb
132
+ - lib/decision_agent/monitoring/monitored_agent.rb
133
+ - lib/decision_agent/monitoring/prometheus_exporter.rb
83
134
  - lib/decision_agent/replay/replay.rb
84
135
  - lib/decision_agent/scoring/base.rb
85
136
  - lib/decision_agent/scoring/consensus.rb
@@ -100,6 +151,7 @@ files:
100
151
  - lib/generators/decision_agent/install/templates/migration.rb
101
152
  - lib/generators/decision_agent/install/templates/rule.rb
102
153
  - lib/generators/decision_agent/install/templates/rule_version.rb
154
+ - spec/activerecord_thread_safety_spec.rb
103
155
  - spec/agent_spec.rb
104
156
  - spec/api_contract_spec.rb
105
157
  - spec/audit_adapters_spec.rb
@@ -107,13 +159,23 @@ files:
107
159
  - spec/context_spec.rb
108
160
  - spec/dsl_validation_spec.rb
109
161
  - spec/edge_cases_spec.rb
162
+ - spec/examples.txt
110
163
  - spec/examples/feedback_aware_evaluator_spec.rb
164
+ - spec/issue_verification_spec.rb
111
165
  - spec/json_rule_evaluator_spec.rb
166
+ - spec/monitoring/alert_manager_spec.rb
167
+ - spec/monitoring/metrics_collector_spec.rb
168
+ - spec/monitoring/monitored_agent_spec.rb
169
+ - spec/monitoring/prometheus_exporter_spec.rb
112
170
  - spec/replay_edge_cases_spec.rb
113
171
  - spec/replay_spec.rb
172
+ - spec/rfc8785_canonicalization_spec.rb
114
173
  - spec/scoring_spec.rb
115
174
  - spec/spec_helper.rb
175
+ - spec/thread_safety_spec.rb
176
+ - spec/thread_safety_spec.rb.broken
116
177
  - spec/versioning_spec.rb
178
+ - spec/web_ui_rack_spec.rb
117
179
  homepage: https://github.com/samaswin87/decision_agent
118
180
  licenses:
119
181
  - MIT
@@ -121,6 +183,7 @@ metadata:
121
183
  homepage_uri: https://github.com/samaswin87/decision_agent
122
184
  source_code_uri: https://github.com/samaswin87/decision_agent
123
185
  changelog_uri: https://github.com/samaswin87/decision_agent/blob/main/CHANGELOG.md
186
+ rubygems_mfa_required: 'true'
124
187
  post_install_message:
125
188
  rdoc_options: []
126
189
  require_paths: