decision_agent 0.1.1 → 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 (66) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +234 -919
  3. data/bin/decision_agent +5 -5
  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 +21 -6
  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 +141 -0
  29. data/lib/decision_agent/versioning/adapter.rb +100 -0
  30. data/lib/decision_agent/versioning/file_storage_adapter.rb +290 -0
  31. data/lib/decision_agent/versioning/version_manager.rb +127 -0
  32. data/lib/decision_agent/web/public/app.js +318 -0
  33. data/lib/decision_agent/web/public/index.html +56 -1
  34. data/lib/decision_agent/web/public/styles.css +219 -0
  35. data/lib/decision_agent/web/server.rb +169 -9
  36. data/lib/decision_agent.rb +11 -0
  37. data/lib/generators/decision_agent/install/install_generator.rb +40 -0
  38. data/lib/generators/decision_agent/install/templates/README +47 -0
  39. data/lib/generators/decision_agent/install/templates/migration.rb +37 -0
  40. data/lib/generators/decision_agent/install/templates/rule.rb +30 -0
  41. data/lib/generators/decision_agent/install/templates/rule_version.rb +66 -0
  42. data/spec/activerecord_thread_safety_spec.rb +553 -0
  43. data/spec/agent_spec.rb +13 -13
  44. data/spec/api_contract_spec.rb +16 -16
  45. data/spec/audit_adapters_spec.rb +3 -3
  46. data/spec/comprehensive_edge_cases_spec.rb +86 -86
  47. data/spec/dsl_validation_spec.rb +83 -83
  48. data/spec/edge_cases_spec.rb +23 -23
  49. data/spec/examples/feedback_aware_evaluator_spec.rb +7 -7
  50. data/spec/examples.txt +548 -0
  51. data/spec/issue_verification_spec.rb +685 -0
  52. data/spec/json_rule_evaluator_spec.rb +15 -15
  53. data/spec/monitoring/alert_manager_spec.rb +378 -0
  54. data/spec/monitoring/metrics_collector_spec.rb +281 -0
  55. data/spec/monitoring/monitored_agent_spec.rb +222 -0
  56. data/spec/monitoring/prometheus_exporter_spec.rb +242 -0
  57. data/spec/replay_edge_cases_spec.rb +58 -58
  58. data/spec/replay_spec.rb +11 -11
  59. data/spec/rfc8785_canonicalization_spec.rb +215 -0
  60. data/spec/scoring_spec.rb +1 -1
  61. data/spec/spec_helper.rb +9 -0
  62. data/spec/thread_safety_spec.rb +482 -0
  63. data/spec/thread_safety_spec.rb.broken +878 -0
  64. data/spec/versioning_spec.rb +777 -0
  65. data/spec/web_ui_rack_spec.rb +135 -0
  66. metadata +84 -11
@@ -4,15 +4,15 @@ RSpec.describe "DSL Validation" do
4
4
  describe DecisionAgent::Dsl::SchemaValidator do
5
5
  describe "root structure validation" do
6
6
  it "rejects non-hash input" do
7
- expect {
7
+ expect do
8
8
  DecisionAgent::Dsl::SchemaValidator.validate!([1, 2, 3])
9
- }.to raise_error(DecisionAgent::InvalidRuleDslError, /Root element must be a hash/)
9
+ end.to raise_error(DecisionAgent::InvalidRuleDslError, /Root element must be a hash/)
10
10
  end
11
11
 
12
12
  it "rejects string input" do
13
- expect {
13
+ expect do
14
14
  DecisionAgent::Dsl::SchemaValidator.validate!("not a hash")
15
- }.to raise_error(DecisionAgent::InvalidRuleDslError, /Root element must be a hash/)
15
+ end.to raise_error(DecisionAgent::InvalidRuleDslError, /Root element must be a hash/)
16
16
  end
17
17
 
18
18
  it "accepts valid hash input" do
@@ -21,9 +21,9 @@ RSpec.describe "DSL Validation" do
21
21
  "rules" => []
22
22
  }
23
23
 
24
- expect {
24
+ expect do
25
25
  DecisionAgent::Dsl::SchemaValidator.validate!(valid_rules)
26
- }.not_to raise_error
26
+ end.not_to raise_error
27
27
  end
28
28
  end
29
29
 
@@ -33,9 +33,9 @@ RSpec.describe "DSL Validation" do
33
33
  "rules" => []
34
34
  }
35
35
 
36
- expect {
36
+ expect do
37
37
  DecisionAgent::Dsl::SchemaValidator.validate!(rules)
38
- }.to raise_error(DecisionAgent::InvalidRuleDslError, /Missing required field 'version'/)
38
+ end.to raise_error(DecisionAgent::InvalidRuleDslError, /Missing required field 'version'/)
39
39
  end
40
40
 
41
41
  it "accepts version as symbol key" do
@@ -44,9 +44,9 @@ RSpec.describe "DSL Validation" do
44
44
  rules: []
45
45
  }
46
46
 
47
- expect {
47
+ expect do
48
48
  DecisionAgent::Dsl::SchemaValidator.validate!(rules)
49
- }.not_to raise_error
49
+ end.not_to raise_error
50
50
  end
51
51
  end
52
52
 
@@ -56,9 +56,9 @@ RSpec.describe "DSL Validation" do
56
56
  "version" => "1.0"
57
57
  }
58
58
 
59
- expect {
59
+ expect do
60
60
  DecisionAgent::Dsl::SchemaValidator.validate!(rules)
61
- }.to raise_error(DecisionAgent::InvalidRuleDslError, /Missing required field 'rules'/)
61
+ end.to raise_error(DecisionAgent::InvalidRuleDslError, /Missing required field 'rules'/)
62
62
  end
63
63
 
64
64
  it "rejects non-array rules" do
@@ -67,9 +67,9 @@ RSpec.describe "DSL Validation" do
67
67
  "rules" => "not an array"
68
68
  }
69
69
 
70
- expect {
70
+ expect do
71
71
  DecisionAgent::Dsl::SchemaValidator.validate!(rules)
72
- }.to raise_error(DecisionAgent::InvalidRuleDslError, /must be an array/)
72
+ end.to raise_error(DecisionAgent::InvalidRuleDslError, /must be an array/)
73
73
  end
74
74
 
75
75
  it "accepts empty rules array" do
@@ -78,9 +78,9 @@ RSpec.describe "DSL Validation" do
78
78
  "rules" => []
79
79
  }
80
80
 
81
- expect {
81
+ expect do
82
82
  DecisionAgent::Dsl::SchemaValidator.validate!(rules)
83
- }.not_to raise_error
83
+ end.not_to raise_error
84
84
  end
85
85
  end
86
86
 
@@ -91,9 +91,9 @@ RSpec.describe "DSL Validation" do
91
91
  "rules" => ["not a hash"]
92
92
  }
93
93
 
94
- expect {
94
+ expect do
95
95
  DecisionAgent::Dsl::SchemaValidator.validate!(rules)
96
- }.to raise_error(DecisionAgent::InvalidRuleDslError, /rules\[0\].*must be a hash/)
96
+ end.to raise_error(DecisionAgent::InvalidRuleDslError, /rules\[0\].*must be a hash/)
97
97
  end
98
98
 
99
99
  it "requires rule id" do
@@ -107,9 +107,9 @@ RSpec.describe "DSL Validation" do
107
107
  ]
108
108
  }
109
109
 
110
- expect {
110
+ expect do
111
111
  DecisionAgent::Dsl::SchemaValidator.validate!(rules)
112
- }.to raise_error(DecisionAgent::InvalidRuleDslError, /Missing required field 'id'/)
112
+ end.to raise_error(DecisionAgent::InvalidRuleDslError, /Missing required field 'id'/)
113
113
  end
114
114
 
115
115
  it "requires rule if clause" do
@@ -123,9 +123,9 @@ RSpec.describe "DSL Validation" do
123
123
  ]
124
124
  }
125
125
 
126
- expect {
126
+ expect do
127
127
  DecisionAgent::Dsl::SchemaValidator.validate!(rules)
128
- }.to raise_error(DecisionAgent::InvalidRuleDslError, /Missing required field 'if'/)
128
+ end.to raise_error(DecisionAgent::InvalidRuleDslError, /Missing required field 'if'/)
129
129
  end
130
130
 
131
131
  it "requires rule then clause" do
@@ -139,9 +139,9 @@ RSpec.describe "DSL Validation" do
139
139
  ]
140
140
  }
141
141
 
142
- expect {
142
+ expect do
143
143
  DecisionAgent::Dsl::SchemaValidator.validate!(rules)
144
- }.to raise_error(DecisionAgent::InvalidRuleDslError, /Missing required field 'then'/)
144
+ end.to raise_error(DecisionAgent::InvalidRuleDslError, /Missing required field 'then'/)
145
145
  end
146
146
  end
147
147
 
@@ -158,9 +158,9 @@ RSpec.describe "DSL Validation" do
158
158
  ]
159
159
  }
160
160
 
161
- expect {
161
+ expect do
162
162
  DecisionAgent::Dsl::SchemaValidator.validate!(rules)
163
- }.to raise_error(DecisionAgent::InvalidRuleDslError, /Condition must have one of: 'field', 'all', or 'any'/)
163
+ end.to raise_error(DecisionAgent::InvalidRuleDslError, /Condition must have one of: 'field', 'all', or 'any'/)
164
164
  end
165
165
 
166
166
  it "rejects non-hash condition" do
@@ -175,9 +175,9 @@ RSpec.describe "DSL Validation" do
175
175
  ]
176
176
  }
177
177
 
178
- expect {
178
+ expect do
179
179
  DecisionAgent::Dsl::SchemaValidator.validate!(rules)
180
- }.to raise_error(DecisionAgent::InvalidRuleDslError, /Condition must be a hash/)
180
+ end.to raise_error(DecisionAgent::InvalidRuleDslError, /Condition must be a hash/)
181
181
  end
182
182
  end
183
183
 
@@ -194,9 +194,9 @@ RSpec.describe "DSL Validation" do
194
194
  ]
195
195
  }
196
196
 
197
- expect {
197
+ expect do
198
198
  DecisionAgent::Dsl::SchemaValidator.validate!(rules)
199
- }.to raise_error(DecisionAgent::InvalidRuleDslError) do |error|
199
+ end.to raise_error(DecisionAgent::InvalidRuleDslError) do |error|
200
200
  expect(error.message).to match(/Condition must have one of: 'field', 'all', or 'any'/)
201
201
  end
202
202
  end
@@ -213,9 +213,9 @@ RSpec.describe "DSL Validation" do
213
213
  ]
214
214
  }
215
215
 
216
- expect {
216
+ expect do
217
217
  DecisionAgent::Dsl::SchemaValidator.validate!(rules)
218
- }.to raise_error(DecisionAgent::InvalidRuleDslError, /missing 'op'/)
218
+ end.to raise_error(DecisionAgent::InvalidRuleDslError, /missing 'op'/)
219
219
  end
220
220
 
221
221
  it "validates operator is supported" do
@@ -230,9 +230,9 @@ RSpec.describe "DSL Validation" do
230
230
  ]
231
231
  }
232
232
 
233
- expect {
233
+ expect do
234
234
  DecisionAgent::Dsl::SchemaValidator.validate!(rules)
235
- }.to raise_error(DecisionAgent::InvalidRuleDslError) do |error|
235
+ end.to raise_error(DecisionAgent::InvalidRuleDslError) do |error|
236
236
  expect(error.message).to include("Unsupported operator 'invalid_op'")
237
237
  expect(error.message).to include("eq, neq, gt, gte, lt, lte, in, present, blank")
238
238
  end
@@ -250,9 +250,9 @@ RSpec.describe "DSL Validation" do
250
250
  ]
251
251
  }
252
252
 
253
- expect {
253
+ expect do
254
254
  DecisionAgent::Dsl::SchemaValidator.validate!(rules)
255
- }.to raise_error(DecisionAgent::InvalidRuleDslError, /missing 'value' key/)
255
+ end.to raise_error(DecisionAgent::InvalidRuleDslError, /missing 'value' key/)
256
256
  end
257
257
 
258
258
  it "allows missing value for present operator" do
@@ -267,9 +267,9 @@ RSpec.describe "DSL Validation" do
267
267
  ]
268
268
  }
269
269
 
270
- expect {
270
+ expect do
271
271
  DecisionAgent::Dsl::SchemaValidator.validate!(rules)
272
- }.not_to raise_error
272
+ end.not_to raise_error
273
273
  end
274
274
 
275
275
  it "allows missing value for blank operator" do
@@ -284,9 +284,9 @@ RSpec.describe "DSL Validation" do
284
284
  ]
285
285
  }
286
286
 
287
- expect {
287
+ expect do
288
288
  DecisionAgent::Dsl::SchemaValidator.validate!(rules)
289
- }.not_to raise_error
289
+ end.not_to raise_error
290
290
  end
291
291
 
292
292
  it "rejects empty field path" do
@@ -301,9 +301,9 @@ RSpec.describe "DSL Validation" do
301
301
  ]
302
302
  }
303
303
 
304
- expect {
304
+ expect do
305
305
  DecisionAgent::Dsl::SchemaValidator.validate!(rules)
306
- }.to raise_error(DecisionAgent::InvalidRuleDslError, /Field path cannot be empty/)
306
+ end.to raise_error(DecisionAgent::InvalidRuleDslError, /Field path cannot be empty/)
307
307
  end
308
308
 
309
309
  it "rejects invalid dot-notation" do
@@ -318,9 +318,9 @@ RSpec.describe "DSL Validation" do
318
318
  ]
319
319
  }
320
320
 
321
- expect {
321
+ expect do
322
322
  DecisionAgent::Dsl::SchemaValidator.validate!(rules)
323
- }.to raise_error(DecisionAgent::InvalidRuleDslError, /cannot have empty segments/)
323
+ end.to raise_error(DecisionAgent::InvalidRuleDslError, /cannot have empty segments/)
324
324
  end
325
325
 
326
326
  it "accepts valid dot-notation" do
@@ -335,9 +335,9 @@ RSpec.describe "DSL Validation" do
335
335
  ]
336
336
  }
337
337
 
338
- expect {
338
+ expect do
339
339
  DecisionAgent::Dsl::SchemaValidator.validate!(rules)
340
- }.not_to raise_error
340
+ end.not_to raise_error
341
341
  end
342
342
  end
343
343
 
@@ -354,9 +354,9 @@ RSpec.describe "DSL Validation" do
354
354
  ]
355
355
  }
356
356
 
357
- expect {
357
+ expect do
358
358
  DecisionAgent::Dsl::SchemaValidator.validate!(rules)
359
- }.to raise_error(DecisionAgent::InvalidRuleDslError, /'all' condition must contain an array/)
359
+ end.to raise_error(DecisionAgent::InvalidRuleDslError, /'all' condition must contain an array/)
360
360
  end
361
361
 
362
362
  it "requires array for any condition" do
@@ -371,9 +371,9 @@ RSpec.describe "DSL Validation" do
371
371
  ]
372
372
  }
373
373
 
374
- expect {
374
+ expect do
375
375
  DecisionAgent::Dsl::SchemaValidator.validate!(rules)
376
- }.to raise_error(DecisionAgent::InvalidRuleDslError, /'any' condition must contain an array/)
376
+ end.to raise_error(DecisionAgent::InvalidRuleDslError, /'any' condition must contain an array/)
377
377
  end
378
378
 
379
379
  it "validates nested conditions in all" do
@@ -392,9 +392,9 @@ RSpec.describe "DSL Validation" do
392
392
  ]
393
393
  }
394
394
 
395
- expect {
395
+ expect do
396
396
  DecisionAgent::Dsl::SchemaValidator.validate!(rules)
397
- }.to raise_error(DecisionAgent::InvalidRuleDslError, /Unsupported operator/)
397
+ end.to raise_error(DecisionAgent::InvalidRuleDslError, /Unsupported operator/)
398
398
  end
399
399
 
400
400
  it "validates nested conditions in any" do
@@ -405,7 +405,7 @@ RSpec.describe "DSL Validation" do
405
405
  "id" => "rule_1",
406
406
  "if" => {
407
407
  "any" => [
408
- { "field" => "priority" } # Missing op
408
+ { "field" => "priority" } # Missing op
409
409
  ]
410
410
  },
411
411
  "then" => { "decision" => "escalate" }
@@ -413,9 +413,9 @@ RSpec.describe "DSL Validation" do
413
413
  ]
414
414
  }
415
415
 
416
- expect {
416
+ expect do
417
417
  DecisionAgent::Dsl::SchemaValidator.validate!(rules)
418
- }.to raise_error(DecisionAgent::InvalidRuleDslError, /missing 'op'/)
418
+ end.to raise_error(DecisionAgent::InvalidRuleDslError, /missing 'op'/)
419
419
  end
420
420
  end
421
421
 
@@ -432,9 +432,9 @@ RSpec.describe "DSL Validation" do
432
432
  ]
433
433
  }
434
434
 
435
- expect {
435
+ expect do
436
436
  DecisionAgent::Dsl::SchemaValidator.validate!(rules)
437
- }.to raise_error(DecisionAgent::InvalidRuleDslError, /then.*Must be a hash/)
437
+ end.to raise_error(DecisionAgent::InvalidRuleDslError, /then.*Must be a hash/)
438
438
  end
439
439
 
440
440
  it "requires decision field in then clause" do
@@ -449,9 +449,9 @@ RSpec.describe "DSL Validation" do
449
449
  ]
450
450
  }
451
451
 
452
- expect {
452
+ expect do
453
453
  DecisionAgent::Dsl::SchemaValidator.validate!(rules)
454
- }.to raise_error(DecisionAgent::InvalidRuleDslError, /Missing required field 'decision'/)
454
+ end.to raise_error(DecisionAgent::InvalidRuleDslError, /Missing required field 'decision'/)
455
455
  end
456
456
 
457
457
  it "validates weight is numeric" do
@@ -466,9 +466,9 @@ RSpec.describe "DSL Validation" do
466
466
  ]
467
467
  }
468
468
 
469
- expect {
469
+ expect do
470
470
  DecisionAgent::Dsl::SchemaValidator.validate!(rules)
471
- }.to raise_error(DecisionAgent::InvalidRuleDslError, /weight.*Must be a number/)
471
+ end.to raise_error(DecisionAgent::InvalidRuleDslError, /weight.*Must be a number/)
472
472
  end
473
473
 
474
474
  it "validates weight is between 0 and 1" do
@@ -483,9 +483,9 @@ RSpec.describe "DSL Validation" do
483
483
  ]
484
484
  }
485
485
 
486
- expect {
486
+ expect do
487
487
  DecisionAgent::Dsl::SchemaValidator.validate!(rules)
488
- }.to raise_error(DecisionAgent::InvalidRuleDslError, /weight.*between 0.0 and 1.0/)
488
+ end.to raise_error(DecisionAgent::InvalidRuleDslError, /weight.*between 0.0 and 1.0/)
489
489
  end
490
490
 
491
491
  it "validates reason is a string" do
@@ -500,9 +500,9 @@ RSpec.describe "DSL Validation" do
500
500
  ]
501
501
  }
502
502
 
503
- expect {
503
+ expect do
504
504
  DecisionAgent::Dsl::SchemaValidator.validate!(rules)
505
- }.to raise_error(DecisionAgent::InvalidRuleDslError, /reason.*Must be a string/)
505
+ end.to raise_error(DecisionAgent::InvalidRuleDslError, /reason.*Must be a string/)
506
506
  end
507
507
 
508
508
  it "accepts valid then clause with all fields" do
@@ -521,9 +521,9 @@ RSpec.describe "DSL Validation" do
521
521
  ]
522
522
  }
523
523
 
524
- expect {
524
+ expect do
525
525
  DecisionAgent::Dsl::SchemaValidator.validate!(rules)
526
- }.not_to raise_error
526
+ end.not_to raise_error
527
527
  end
528
528
  end
529
529
 
@@ -533,16 +533,16 @@ RSpec.describe "DSL Validation" do
533
533
  "version" => "1.0",
534
534
  "rules" => [
535
535
  {
536
- "id" => "rule_1",
536
+ "id" => "rule_1"
537
537
  # Missing if clause
538
538
  # Missing then clause
539
539
  }
540
540
  ]
541
541
  }
542
542
 
543
- expect {
543
+ expect do
544
544
  DecisionAgent::Dsl::SchemaValidator.validate!(rules)
545
- }.to raise_error(DecisionAgent::InvalidRuleDslError) do |error|
545
+ end.to raise_error(DecisionAgent::InvalidRuleDslError) do |error|
546
546
  expect(error.message).to include("1.")
547
547
  expect(error.message).to include("2.")
548
548
  expect(error.message).to match(/validation failed with 2 errors/)
@@ -561,9 +561,9 @@ RSpec.describe "DSL Validation" do
561
561
  ]
562
562
  }
563
563
 
564
- expect {
564
+ expect do
565
565
  DecisionAgent::Dsl::SchemaValidator.validate!(rules)
566
- }.to raise_error(DecisionAgent::InvalidRuleDslError) do |error|
566
+ end.to raise_error(DecisionAgent::InvalidRuleDslError) do |error|
567
567
  expect(error.message).to include("rules[0].if")
568
568
  expect(error.message).to include("Supported operators:")
569
569
  end
@@ -592,9 +592,9 @@ RSpec.describe "DSL Validation" do
592
592
  ]
593
593
  }
594
594
 
595
- expect {
595
+ expect do
596
596
  DecisionAgent::Dsl::SchemaValidator.validate!(rules)
597
- }.to raise_error(DecisionAgent::InvalidRuleDslError) do |error|
597
+ end.to raise_error(DecisionAgent::InvalidRuleDslError) do |error|
598
598
  expect(error.message).to include("rules[0].if.all[0].any[1]")
599
599
  expect(error.message).to include("Unsupported operator")
600
600
  end
@@ -606,17 +606,17 @@ RSpec.describe "DSL Validation" do
606
606
  it "uses SchemaValidator for validation" do
607
607
  invalid_json = '{"version": "1.0", "rules": "not an array"}'
608
608
 
609
- expect {
609
+ expect do
610
610
  DecisionAgent::Dsl::RuleParser.parse(invalid_json)
611
- }.to raise_error(DecisionAgent::InvalidRuleDslError, /must be an array/)
611
+ end.to raise_error(DecisionAgent::InvalidRuleDslError, /must be an array/)
612
612
  end
613
613
 
614
614
  it "provides helpful error for malformed JSON" do
615
615
  malformed_json = '{"version": "1.0", "rules": [,,,]}'
616
616
 
617
- expect {
617
+ expect do
618
618
  DecisionAgent::Dsl::RuleParser.parse(malformed_json)
619
- }.to raise_error(DecisionAgent::InvalidRuleDslError) do |error|
619
+ end.to raise_error(DecisionAgent::InvalidRuleDslError) do |error|
620
620
  expect(error.message).to include("Invalid JSON syntax")
621
621
  expect(error.message).to include("Common issues")
622
622
  end
@@ -634,15 +634,15 @@ RSpec.describe "DSL Validation" do
634
634
  ]
635
635
  }
636
636
 
637
- expect {
637
+ expect do
638
638
  DecisionAgent::Dsl::RuleParser.parse(rules_hash)
639
- }.not_to raise_error
639
+ end.not_to raise_error
640
640
  end
641
641
 
642
642
  it "rejects invalid input types" do
643
- expect {
644
- DecisionAgent::Dsl::RuleParser.parse(12345)
645
- }.to raise_error(DecisionAgent::InvalidRuleDslError, /Expected JSON string or Hash/)
643
+ expect do
644
+ DecisionAgent::Dsl::RuleParser.parse(12_345)
645
+ end.to raise_error(DecisionAgent::InvalidRuleDslError, /Expected JSON string or Hash/)
646
646
  end
647
647
  end
648
648
  end
@@ -47,7 +47,7 @@ RSpec.describe "Edge Cases" do
47
47
 
48
48
  describe "confidence edge cases" do
49
49
  it "raises error when confidence exceeds 1.0" do
50
- expect {
50
+ expect do
51
51
  DecisionAgent::Decision.new(
52
52
  decision: "test",
53
53
  confidence: 1.5,
@@ -55,11 +55,11 @@ RSpec.describe "Edge Cases" do
55
55
  evaluations: [],
56
56
  audit_payload: {}
57
57
  )
58
- }.to raise_error(DecisionAgent::InvalidConfidenceError)
58
+ end.to raise_error(DecisionAgent::InvalidConfidenceError)
59
59
  end
60
60
 
61
61
  it "raises error when confidence is negative" do
62
- expect {
62
+ expect do
63
63
  DecisionAgent::Decision.new(
64
64
  decision: "test",
65
65
  confidence: -0.1,
@@ -67,7 +67,7 @@ RSpec.describe "Edge Cases" do
67
67
  evaluations: [],
68
68
  audit_payload: {}
69
69
  )
70
- }.to raise_error(DecisionAgent::InvalidConfidenceError)
70
+ end.to raise_error(DecisionAgent::InvalidConfidenceError)
71
71
  end
72
72
 
73
73
  it "accepts confidence at boundary values" do
@@ -94,25 +94,25 @@ RSpec.describe "Edge Cases" do
94
94
 
95
95
  describe "weight edge cases" do
96
96
  it "raises error when weight exceeds 1.0" do
97
- expect {
97
+ expect do
98
98
  DecisionAgent::Evaluation.new(
99
99
  decision: "test",
100
100
  weight: 1.5,
101
101
  reason: "test",
102
102
  evaluator_name: "test"
103
103
  )
104
- }.to raise_error(DecisionAgent::InvalidWeightError)
104
+ end.to raise_error(DecisionAgent::InvalidWeightError)
105
105
  end
106
106
 
107
107
  it "raises error when weight is negative" do
108
- expect {
108
+ expect do
109
109
  DecisionAgent::Evaluation.new(
110
110
  decision: "test",
111
111
  weight: -0.1,
112
112
  reason: "test",
113
113
  evaluator_name: "test"
114
114
  )
115
- }.to raise_error(DecisionAgent::InvalidWeightError)
115
+ end.to raise_error(DecisionAgent::InvalidWeightError)
116
116
  end
117
117
 
118
118
  it "accepts weight at boundary values" do
@@ -206,9 +206,9 @@ RSpec.describe "Edge Cases" do
206
206
  it "freezes context data to prevent modification" do
207
207
  context = DecisionAgent::Context.new({ user: "alice" })
208
208
 
209
- expect {
209
+ expect do
210
210
  context.to_h[:user] = "bob"
211
- }.to raise_error(FrozenError)
211
+ end.to raise_error(FrozenError)
212
212
  end
213
213
 
214
214
  it "freezes evaluation fields" do
@@ -313,16 +313,16 @@ RSpec.describe "Edge Cases" do
313
313
 
314
314
  evaluator = DecisionAgent::Evaluators::JsonRuleEvaluator.new(rules_json: rules)
315
315
  context = DecisionAgent::Context.new({
316
- a: {
317
- b: {
318
- c: {
319
- d: {
320
- e: "deep"
321
- }
322
- }
323
- }
324
- }
325
- })
316
+ a: {
317
+ b: {
318
+ c: {
319
+ d: {
320
+ e: "deep"
321
+ }
322
+ }
323
+ }
324
+ }
325
+ })
326
326
 
327
327
  evaluation = evaluator.evaluate(context)
328
328
 
@@ -334,7 +334,7 @@ RSpec.describe "Edge Cases" do
334
334
  describe "audit adapter errors" do
335
335
  it "propagates errors from audit adapter" do
336
336
  failing_adapter = Class.new(DecisionAgent::Audit::Adapter) do
337
- def record(decision, context)
337
+ def record(_decision, _context)
338
338
  raise StandardError, "Audit failed"
339
339
  end
340
340
  end
@@ -345,9 +345,9 @@ RSpec.describe "Edge Cases" do
345
345
  audit_adapter: failing_adapter.new
346
346
  )
347
347
 
348
- expect {
348
+ expect do
349
349
  agent.decide(context: {})
350
- }.to raise_error(StandardError, "Audit failed")
350
+ end.to raise_error(StandardError, "Audit failed")
351
351
  end
352
352
  end
353
353
  end
@@ -152,7 +152,7 @@ RSpec.describe Examples::FeedbackAwareEvaluator do
152
152
  it "clamps weight to minimum 0.0" do
153
153
  result = evaluator.evaluate(
154
154
  context,
155
- feedback: { past_accuracy: -1.0 } # Invalid, but should be handled
155
+ feedback: { past_accuracy: -1.0 } # Invalid, but should be handled
156
156
  )
157
157
 
158
158
  expect(result.weight).to be >= 0.0
@@ -161,7 +161,7 @@ RSpec.describe Examples::FeedbackAwareEvaluator do
161
161
  it "clamps weight to maximum 1.0" do
162
162
  result = evaluator.evaluate(
163
163
  context,
164
- feedback: { past_accuracy: 2.0 } # Would produce 1.6, should clamp to 1.0
164
+ feedback: { past_accuracy: 2.0 } # Would produce 1.6, should clamp to 1.0
165
165
  )
166
166
 
167
167
  expect(result.weight).to be <= 1.0
@@ -254,7 +254,7 @@ RSpec.describe Examples::FeedbackAwareEvaluator do
254
254
 
255
255
  result = high_weight_evaluator.evaluate(
256
256
  context,
257
- feedback: { source: "expert_review" } # 0.9 * 1.2 = 1.08, should clamp to 1.0
257
+ feedback: { source: "expert_review" } # 0.9 * 1.2 = 1.08, should clamp to 1.0
258
258
  )
259
259
 
260
260
  expect(result.weight).to eq(1.0)
@@ -330,7 +330,7 @@ RSpec.describe Examples::FeedbackAwareEvaluator do
330
330
  )
331
331
 
332
332
  expect(result.decision).to eq("approve")
333
- expect(result.confidence).to eq(1.0) # Single evaluator normalized to 1.0
333
+ expect(result.confidence).to eq(1.0) # Single evaluator normalized to 1.0
334
334
  end
335
335
 
336
336
  it "respects feedback in agent context" do
@@ -357,7 +357,7 @@ RSpec.describe Examples::FeedbackAwareEvaluator do
357
357
 
358
358
  result = agent.decide(
359
359
  context: {},
360
- feedback: { past_accuracy: 0.5 } # Reduces feedback_eval weight to 0.4
360
+ feedback: { past_accuracy: 0.5 } # Reduces feedback_eval weight to 0.4
361
361
  )
362
362
 
363
363
  expect(result.decision).to eq("approve")
@@ -385,7 +385,7 @@ RSpec.describe Examples::FeedbackAwareEvaluator do
385
385
 
386
386
  result_with_feedback = agent.decide(
387
387
  context: {},
388
- feedback: { past_accuracy: 0.5 } # Reduces feedback_eval to 0.4
388
+ feedback: { past_accuracy: 0.5 } # Reduces feedback_eval to 0.4
389
389
  )
390
390
  # MaxWeight still picks static_eval (0.9 > 0.4)
391
391
  expect(result_with_feedback.decision).to eq("reject")
@@ -399,7 +399,7 @@ RSpec.describe Examples::FeedbackAwareEvaluator do
399
399
  it "handles feedback with string keys" do
400
400
  result = evaluator.evaluate(
401
401
  context,
402
- feedback: { "override" => "reject" } # String key instead of symbol
402
+ feedback: { "override" => "reject" } # String key instead of symbol
403
403
  )
404
404
 
405
405
  # Should not match because code expects symbols