shak3008 commited on
Commit
64ae4f1
·
1 Parent(s): 0868c75

test: verify validation decision rules

Browse files
Files changed (1) hide show
  1. backend/test_validation_proof.py +435 -0
backend/test_validation_proof.py ADDED
@@ -0,0 +1,435 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ from types import SimpleNamespace
4
+
5
+ from app.database.session import SessionLocal
6
+ from app.models.rule import Rule, RuleType
7
+ from app.repositories.rule_repository import RuleRepository
8
+ from app.agents.validation import RuleValidationAgent
9
+ from app.agents.decision import DecisionAgent
10
+
11
+
12
+ print("=" * 60)
13
+ print("DOCWEAVE REAL VALIDATION PROOF")
14
+ print("=" * 60)
15
+
16
+ db = SessionLocal()
17
+
18
+ created_rules = []
19
+
20
+ try:
21
+ # --------------------------------------------------------------
22
+ # Find a real workspace
23
+ # --------------------------------------------------------------
24
+
25
+ from app.models.workspace import Workspace
26
+
27
+ workspace = db.query(Workspace).first()
28
+
29
+ if workspace is None:
30
+ raise RuntimeError("No workspace found.")
31
+
32
+ print("WORKSPACE:", workspace.id)
33
+
34
+ # --------------------------------------------------------------
35
+ # Synthetic proposals
36
+ #
37
+ # These are lightweight proposal-shaped objects because the
38
+ # RuleValidationAgent only needs id, proposal_type and
39
+ # proposed_changes.
40
+ # --------------------------------------------------------------
41
+
42
+ passing_proposal = SimpleNamespace(
43
+ id="proposal-pass",
44
+ proposal_type="CREATE",
45
+ proposed_changes={
46
+ "type": "ENTITY",
47
+ "title": "Congenital Heart Valve Disease",
48
+ "value": "Congenital Heart Valve Disease",
49
+ "confidence": 0.95,
50
+ "evidence": [
51
+ {
52
+ "document_version_id": "synthetic-version",
53
+ "page": 1,
54
+ "text": "Evidence supporting the entity.",
55
+ }
56
+ ],
57
+ },
58
+ )
59
+
60
+ failing_proposal = SimpleNamespace(
61
+ id="proposal-fail",
62
+ proposal_type="CREATE",
63
+ proposed_changes={
64
+ "type": "ENTITY",
65
+ "title": "Low Confidence Entity",
66
+ "value": "Low Confidence Entity",
67
+ "confidence": 0.40,
68
+ },
69
+ )
70
+
71
+ update_proposal = SimpleNamespace(
72
+ id="proposal-update",
73
+ proposal_type="UPDATE",
74
+ proposed_changes={
75
+ "type": "ENTITY",
76
+ "title": "Updated Entity",
77
+ "value": "Updated Entity",
78
+ "confidence": 0.95,
79
+ "evidence": [
80
+ {
81
+ "document_version_id": "synthetic-version",
82
+ "page": 2,
83
+ "text": "Update evidence.",
84
+ }
85
+ ],
86
+ },
87
+ )
88
+
89
+ agent = RuleValidationAgent()
90
+ decision_agent = DecisionAgent()
91
+ repository = RuleRepository(db)
92
+
93
+ # --------------------------------------------------------------
94
+ # Helper
95
+ # --------------------------------------------------------------
96
+
97
+ def make_rule(
98
+ name,
99
+ operator,
100
+ configuration,
101
+ enabled=True,
102
+ ):
103
+ rule = Rule(
104
+ workspace_id=workspace.id,
105
+ name=name,
106
+ description="Validation proof rule",
107
+ rule_type=RuleType.VALIDATION,
108
+ configuration={
109
+ "operator": operator,
110
+ **configuration,
111
+ },
112
+ enabled=enabled,
113
+ )
114
+
115
+ db.add(rule)
116
+ db.flush()
117
+
118
+ created_rules.append(rule)
119
+
120
+ return rule
121
+
122
+ # ==============================================================
123
+ # 1. PASS
124
+ # ==============================================================
125
+
126
+ print()
127
+ print("1. TESTING PASS")
128
+
129
+ pass_rule = make_rule(
130
+ "TEST Required Evidence PASS",
131
+ "required_evidence",
132
+ {},
133
+ )
134
+
135
+ results = agent.validate(
136
+ rules=[pass_rule],
137
+ proposals=[passing_proposal],
138
+ )
139
+
140
+ print("RESULT:", results)
141
+
142
+ assert len(results) == 1
143
+ assert results[0]["status"] == "PASS"
144
+ assert "proposal-pass" in results[0]["proposal_ids"]
145
+
146
+ print("PASS TEST: OK")
147
+
148
+ # ==============================================================
149
+ # 2. FAIL - missing evidence
150
+ # ==============================================================
151
+
152
+ print()
153
+ print("2. TESTING FAIL")
154
+
155
+ evidence_fail_rule = make_rule(
156
+ "TEST Required Evidence FAIL",
157
+ "required_evidence",
158
+ {},
159
+ )
160
+
161
+ results = agent.validate(
162
+ rules=[evidence_fail_rule],
163
+ proposals=[failing_proposal],
164
+ )
165
+
166
+ print("RESULT:", results)
167
+
168
+ assert len(results) == 1
169
+ assert results[0]["status"] == "FAIL"
170
+ assert results[0]["severity"] == "HIGH"
171
+ assert "proposal-fail" in results[0]["proposal_ids"]
172
+
173
+ decision = decision_agent.decide(results)
174
+
175
+ print("DECISION:", decision)
176
+
177
+ assert decision["decision"] == "REVIEW"
178
+ assert decision["failure_count"] == 1
179
+ assert "proposal-fail" in decision["affected_proposal_ids"]
180
+
181
+ print("FAIL TEST: OK")
182
+
183
+ # ==============================================================
184
+ # 3. WARNING - malformed min_confidence
185
+ # ==============================================================
186
+
187
+ print()
188
+ print("3. TESTING WARNING")
189
+
190
+ warning_rule = make_rule(
191
+ "TEST Malformed Confidence Rule",
192
+ "min_confidence",
193
+ {
194
+ "value": "not-a-number",
195
+ },
196
+ )
197
+
198
+ results = agent.validate(
199
+ rules=[warning_rule],
200
+ proposals=[passing_proposal],
201
+ )
202
+
203
+ print("RESULT:", results)
204
+
205
+ assert len(results) == 1
206
+ assert results[0]["status"] == "WARNING"
207
+ assert results[0]["severity"] == "HIGH"
208
+
209
+ decision = decision_agent.decide(results)
210
+
211
+ print("DECISION:", decision)
212
+
213
+ assert decision["decision"] == "REVIEW"
214
+ assert decision["warning_count"] == 1
215
+
216
+ print("WARNING TEST: OK")
217
+
218
+ # ==============================================================
219
+ # 4. MIN CONFIDENCE FAIL
220
+ # ==============================================================
221
+
222
+ print()
223
+ print("4. TESTING MIN CONFIDENCE FAIL")
224
+
225
+ confidence_rule = make_rule(
226
+ "TEST Minimum Confidence",
227
+ "min_confidence",
228
+ {
229
+ "value": 0.80,
230
+ },
231
+ )
232
+
233
+ results = agent.validate(
234
+ rules=[confidence_rule],
235
+ proposals=[failing_proposal],
236
+ )
237
+
238
+ print("RESULT:", results)
239
+
240
+ assert len(results) == 1
241
+ assert results[0]["status"] == "FAIL"
242
+ assert results[0]["operator"] == "min_confidence"
243
+ assert "proposal-fail" in results[0]["proposal_ids"]
244
+
245
+ print("MIN CONFIDENCE TEST: OK")
246
+
247
+ # ==============================================================
248
+ # 5. MIN CONFIDENCE PASS
249
+ # ==============================================================
250
+
251
+ print()
252
+ print("5. TESTING MIN CONFIDENCE PASS")
253
+
254
+ results = agent.validate(
255
+ rules=[confidence_rule],
256
+ proposals=[passing_proposal],
257
+ )
258
+
259
+ print("RESULT:", results)
260
+
261
+ assert len(results) == 1
262
+ assert results[0]["status"] == "PASS"
263
+
264
+ print("MIN CONFIDENCE PASS TEST: OK")
265
+
266
+ # ==============================================================
267
+ # 6. ALLOWED PROPOSAL TYPES FAIL
268
+ # ==============================================================
269
+
270
+ print()
271
+ print("6. TESTING ALLOWED PROPOSAL TYPES FAIL")
272
+
273
+ type_rule = make_rule(
274
+ "TEST Allowed Proposal Types",
275
+ "allowed_proposal_types",
276
+ {
277
+ "values": ["UPDATE"],
278
+ },
279
+ )
280
+
281
+ results = agent.validate(
282
+ rules=[type_rule],
283
+ proposals=[passing_proposal],
284
+ )
285
+
286
+ print("RESULT:", results)
287
+
288
+ assert len(results) == 1
289
+ assert results[0]["status"] == "FAIL"
290
+ assert results[0]["operator"] == "allowed_proposal_types"
291
+
292
+ print("PROPOSAL TYPE FAIL TEST: OK")
293
+
294
+ # ==============================================================
295
+ # 7. ALLOWED PROPOSAL TYPES PASS
296
+ # ==============================================================
297
+
298
+ print()
299
+ print("7. TESTING ALLOWED PROPOSAL TYPES PASS")
300
+
301
+ results = agent.validate(
302
+ rules=[type_rule],
303
+ proposals=[update_proposal],
304
+ )
305
+
306
+ print("RESULT:", results)
307
+
308
+ assert len(results) == 1
309
+ assert results[0]["status"] == "PASS"
310
+
311
+ print("PROPOSAL TYPE PASS TEST: OK")
312
+
313
+ # ==============================================================
314
+ # 8. UNKNOWN OPERATOR → WARNING
315
+ # ==============================================================
316
+
317
+ print()
318
+ print("8. TESTING UNKNOWN OPERATOR")
319
+
320
+ unknown_rule = make_rule(
321
+ "TEST Unknown Operator",
322
+ "does_not_exist",
323
+ {},
324
+ )
325
+
326
+ results = agent.validate(
327
+ rules=[unknown_rule],
328
+ proposals=[passing_proposal],
329
+ )
330
+
331
+ print("RESULT:", results)
332
+
333
+ assert len(results) == 1
334
+ assert results[0]["status"] == "WARNING"
335
+ assert results[0]["operator"] == "does_not_exist"
336
+
337
+ print("UNKNOWN OPERATOR TEST: OK")
338
+
339
+ # ==============================================================
340
+ # 9. DISABLED RULE MUST BE IGNORED
341
+ # ==============================================================
342
+
343
+ print()
344
+ print("9. TESTING DISABLED RULE")
345
+
346
+ disabled_rule = make_rule(
347
+ "TEST Disabled Rule",
348
+ "required_evidence",
349
+ {},
350
+ enabled=False,
351
+ )
352
+
353
+ db.commit()
354
+
355
+ enabled_rules = repository.list_enabled(
356
+ workspace.id
357
+ )
358
+
359
+ enabled_rule_ids = {
360
+ str(rule.id)
361
+ for rule in enabled_rules
362
+ }
363
+
364
+ print(
365
+ "DISABLED RULE:",
366
+ disabled_rule.id,
367
+ )
368
+
369
+ print(
370
+ "ENABLED RULE COUNT:",
371
+ len(enabled_rules),
372
+ )
373
+
374
+ assert str(disabled_rule.id) not in enabled_rule_ids
375
+
376
+ print("DISABLED RULE TEST: OK")
377
+
378
+ # ==============================================================
379
+ # 10. NO RULES → PASS
380
+ # ==============================================================
381
+
382
+ print()
383
+ print("10. TESTING NO ENABLED RULES")
384
+
385
+ results = agent.validate(
386
+ rules=[],
387
+ proposals=[passing_proposal],
388
+ )
389
+
390
+ print("RESULT:", results)
391
+
392
+ assert len(results) == 1
393
+ assert results[0]["status"] == "PASS"
394
+ assert results[0]["rule_name"] == "No enabled rules"
395
+
396
+ decision = decision_agent.decide(results)
397
+
398
+ print("DECISION:", decision)
399
+
400
+ assert decision["decision"] == "CONTINUE"
401
+
402
+ print("NO RULES TEST: OK")
403
+
404
+ # ==============================================================
405
+ # FINAL CLEANUP
406
+ # ==============================================================
407
+
408
+ for rule in created_rules:
409
+ db.delete(rule)
410
+
411
+ db.commit()
412
+
413
+ # ==============================================================
414
+ # SUCCESS
415
+ # ==============================================================
416
+
417
+ print()
418
+ print("=" * 60)
419
+ print("PASS: REAL VALIDATION ENGINE VERIFIED")
420
+ print("=" * 60)
421
+ print()
422
+ print("PASS RULES: OK")
423
+ print("FAIL RULES: OK")
424
+ print("WARNING RULES: OK")
425
+ print("MIN CONFIDENCE: OK")
426
+ print("PROPOSAL TYPE RULES: OK")
427
+ print("UNKNOWN OPERATOR: OK")
428
+ print("DISABLED RULE: OK")
429
+ print("NO ENABLED RULES: OK")
430
+ print("DECISION ROUTING: OK")
431
+ print()
432
+
433
+ finally:
434
+ db.rollback()
435
+ db.close()