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
@@ -0,0 +1,381 @@
1
+ * {
2
+ margin: 0;
3
+ padding: 0;
4
+ box-sizing: border-box;
5
+ }
6
+
7
+ body {
8
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
9
+ background: #0f1419;
10
+ color: #e6edf3;
11
+ line-height: 1.6;
12
+ }
13
+
14
+ .dashboard {
15
+ max-width: 1600px;
16
+ margin: 0 auto;
17
+ padding: 20px;
18
+ }
19
+
20
+ .header {
21
+ display: flex;
22
+ justify-content: space-between;
23
+ align-items: center;
24
+ margin-bottom: 30px;
25
+ padding: 20px;
26
+ background: #161b22;
27
+ border-radius: 8px;
28
+ border: 1px solid #30363d;
29
+ }
30
+
31
+ .header h1 {
32
+ font-size: 28px;
33
+ color: #58a6ff;
34
+ }
35
+
36
+ .header-info {
37
+ display: flex;
38
+ gap: 20px;
39
+ align-items: center;
40
+ }
41
+
42
+ .status-badge {
43
+ padding: 6px 12px;
44
+ border-radius: 20px;
45
+ font-size: 14px;
46
+ font-weight: 600;
47
+ }
48
+
49
+ .status-badge.connected {
50
+ background: #238636;
51
+ color: #fff;
52
+ }
53
+
54
+ .status-badge.disconnected {
55
+ background: #da3633;
56
+ color: #fff;
57
+ }
58
+
59
+ #last-update {
60
+ color: #8b949e;
61
+ font-size: 14px;
62
+ }
63
+
64
+ .alert-bar {
65
+ background: #da3633;
66
+ color: #fff;
67
+ padding: 15px 20px;
68
+ margin-bottom: 20px;
69
+ border-radius: 8px;
70
+ display: flex;
71
+ justify-content: space-between;
72
+ align-items: center;
73
+ }
74
+
75
+ .alert-content {
76
+ display: flex;
77
+ align-items: center;
78
+ gap: 10px;
79
+ width: 100%;
80
+ }
81
+
82
+ .alert-icon {
83
+ font-size: 24px;
84
+ }
85
+
86
+ .alert-close {
87
+ background: none;
88
+ border: none;
89
+ color: #fff;
90
+ font-size: 24px;
91
+ cursor: pointer;
92
+ padding: 0 10px;
93
+ }
94
+
95
+ .metrics-grid {
96
+ display: grid;
97
+ grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
98
+ gap: 20px;
99
+ margin-bottom: 30px;
100
+ }
101
+
102
+ .metric-card {
103
+ background: #161b22;
104
+ padding: 24px;
105
+ border-radius: 8px;
106
+ border: 1px solid #30363d;
107
+ transition: transform 0.2s, box-shadow 0.2s;
108
+ }
109
+
110
+ .metric-card:hover {
111
+ transform: translateY(-2px);
112
+ box-shadow: 0 4px 12px rgba(88, 166, 255, 0.1);
113
+ }
114
+
115
+ .metric-card.error-card {
116
+ border-color: #da3633;
117
+ }
118
+
119
+ .metric-label {
120
+ font-size: 14px;
121
+ color: #8b949e;
122
+ margin-bottom: 8px;
123
+ }
124
+
125
+ .metric-value {
126
+ font-size: 32px;
127
+ font-weight: 700;
128
+ color: #58a6ff;
129
+ margin-bottom: 8px;
130
+ }
131
+
132
+ .metric-change {
133
+ font-size: 12px;
134
+ color: #8b949e;
135
+ }
136
+
137
+ .metric-change.positive {
138
+ color: #3fb950;
139
+ }
140
+
141
+ .metric-change.negative {
142
+ color: #da3633;
143
+ }
144
+
145
+ .charts-grid {
146
+ display: grid;
147
+ grid-template-columns: repeat(auto-fit, minmax(500px, 1fr));
148
+ gap: 20px;
149
+ margin-bottom: 30px;
150
+ }
151
+
152
+ .chart-card {
153
+ background: #161b22;
154
+ padding: 24px;
155
+ border-radius: 8px;
156
+ border: 1px solid #30363d;
157
+ }
158
+
159
+ .chart-card h3 {
160
+ margin-bottom: 20px;
161
+ color: #e6edf3;
162
+ font-size: 18px;
163
+ }
164
+
165
+ .data-grid {
166
+ display: grid;
167
+ grid-template-columns: repeat(auto-fit, minmax(600px, 1fr));
168
+ gap: 20px;
169
+ margin-bottom: 30px;
170
+ }
171
+
172
+ .data-card {
173
+ background: #161b22;
174
+ padding: 24px;
175
+ border-radius: 8px;
176
+ border: 1px solid #30363d;
177
+ }
178
+
179
+ .data-header {
180
+ display: flex;
181
+ justify-content: space-between;
182
+ align-items: center;
183
+ margin-bottom: 20px;
184
+ }
185
+
186
+ .data-header h3 {
187
+ color: #e6edf3;
188
+ font-size: 18px;
189
+ }
190
+
191
+ .btn-small {
192
+ background: #238636;
193
+ color: #fff;
194
+ border: none;
195
+ padding: 6px 12px;
196
+ border-radius: 6px;
197
+ cursor: pointer;
198
+ font-size: 14px;
199
+ transition: background 0.2s;
200
+ }
201
+
202
+ .btn-small:hover {
203
+ background: #2ea043;
204
+ }
205
+
206
+ .btn-primary {
207
+ background: #58a6ff;
208
+ color: #0d1117;
209
+ border: none;
210
+ padding: 10px 20px;
211
+ border-radius: 6px;
212
+ cursor: pointer;
213
+ font-size: 14px;
214
+ font-weight: 600;
215
+ transition: background 0.2s;
216
+ }
217
+
218
+ .btn-primary:hover {
219
+ background: #79c0ff;
220
+ }
221
+
222
+ .table-container {
223
+ overflow-x: auto;
224
+ }
225
+
226
+ table {
227
+ width: 100%;
228
+ border-collapse: collapse;
229
+ }
230
+
231
+ thead {
232
+ background: #0d1117;
233
+ }
234
+
235
+ th {
236
+ padding: 12px;
237
+ text-align: left;
238
+ color: #8b949e;
239
+ font-weight: 600;
240
+ font-size: 12px;
241
+ text-transform: uppercase;
242
+ border-bottom: 1px solid #30363d;
243
+ }
244
+
245
+ td {
246
+ padding: 12px;
247
+ border-bottom: 1px solid #21262d;
248
+ color: #e6edf3;
249
+ }
250
+
251
+ tr:hover {
252
+ background: #0d1117;
253
+ }
254
+
255
+ .no-data {
256
+ text-align: center;
257
+ color: #8b949e;
258
+ padding: 40px !important;
259
+ }
260
+
261
+ .severity-badge {
262
+ padding: 4px 8px;
263
+ border-radius: 4px;
264
+ font-size: 12px;
265
+ font-weight: 600;
266
+ }
267
+
268
+ .severity-critical {
269
+ background: #da3633;
270
+ color: #fff;
271
+ }
272
+
273
+ .severity-warning {
274
+ background: #d29922;
275
+ color: #0d1117;
276
+ }
277
+
278
+ .severity-info {
279
+ background: #58a6ff;
280
+ color: #0d1117;
281
+ }
282
+
283
+ .alert-actions {
284
+ display: flex;
285
+ gap: 8px;
286
+ }
287
+
288
+ .alert-actions button {
289
+ background: #238636;
290
+ color: #fff;
291
+ border: none;
292
+ padding: 4px 10px;
293
+ border-radius: 4px;
294
+ cursor: pointer;
295
+ font-size: 12px;
296
+ }
297
+
298
+ .alert-actions button:hover {
299
+ background: #2ea043;
300
+ }
301
+
302
+ .system-metrics {
303
+ display: grid;
304
+ gap: 16px;
305
+ }
306
+
307
+ .system-metric {
308
+ display: flex;
309
+ justify-content: space-between;
310
+ padding: 12px 0;
311
+ border-bottom: 1px solid #21262d;
312
+ }
313
+
314
+ .system-metric:last-child {
315
+ border-bottom: none;
316
+ }
317
+
318
+ .metric-name {
319
+ color: #8b949e;
320
+ font-size: 14px;
321
+ }
322
+
323
+ .metric-val {
324
+ color: #58a6ff;
325
+ font-weight: 600;
326
+ font-size: 14px;
327
+ }
328
+
329
+ .kpi-section {
330
+ background: #161b22;
331
+ padding: 24px;
332
+ border-radius: 8px;
333
+ border: 1px solid #30363d;
334
+ }
335
+
336
+ .kpi-section h3 {
337
+ margin-bottom: 20px;
338
+ color: #e6edf3;
339
+ font-size: 18px;
340
+ }
341
+
342
+ .form-group {
343
+ display: flex;
344
+ gap: 12px;
345
+ align-items: center;
346
+ }
347
+
348
+ .form-group input {
349
+ flex: 1;
350
+ background: #0d1117;
351
+ border: 1px solid #30363d;
352
+ color: #e6edf3;
353
+ padding: 10px 12px;
354
+ border-radius: 6px;
355
+ font-size: 14px;
356
+ }
357
+
358
+ .form-group input:focus {
359
+ outline: none;
360
+ border-color: #58a6ff;
361
+ }
362
+
363
+ @media (max-width: 768px) {
364
+ .metrics-grid {
365
+ grid-template-columns: 1fr;
366
+ }
367
+
368
+ .charts-grid {
369
+ grid-template-columns: 1fr;
370
+ }
371
+
372
+ .data-grid {
373
+ grid-template-columns: 1fr;
374
+ }
375
+
376
+ .header {
377
+ flex-direction: column;
378
+ gap: 15px;
379
+ text-align: center;
380
+ }
381
+ }